添加授权时缺少身份验证方案

Posted

技术标签:

【中文标题】添加授权时缺少身份验证方案【英文标题】:Authentication scheme missing when adding authorize 【发布时间】:2020-10-13 00:45:20 【问题描述】:

错误:没有指定 authenticationScheme,也没有找到 DefaultChallengeScheme。

我正在创建两个应用程序:WebApi,这项工作我遵循教程:WebApi Core

在运行邮递员时,这很好用。我遇到的问题是尝试创建使用 web api 的 asp.net 核心,我正在关注本教程:Client Side

所以这就是我所拥有的

两个控制器HomeController、AccountController

帐户控制器

    public class AccountController : Controller
    
        [HttpGet]
        public IActionResult Login()
        
            return View();
        

        [HttpPost]
        [AutoValidateAntiforgeryToken]
        public IActionResult Login(AuthenticatedUser user)
        
            string baseUrl = "http://localhost:8080";
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(baseUrl);
            var contentType = new MediaTypeWithQualityHeaderValue("application/json");
            client.DefaultRequestHeaders.Accept.Add(contentType);

            AuthenticatedUser userModel = new AuthenticatedUser();
            userModel.Username = user.Username;
            userModel.Password = user.Password;

            string stringData = JsonConvert.SerializeObject(userModel);
            var contentData = new StringContent(stringData, System.Text.Encoding.UTF8, "application/json");

            HttpResponseMessage response = client.PostAsync("/Token", contentData).Result;
            string stringJWT = response.Content.ReadAsStringAsync().Result;
            JWT jwt = JsonConvert.DeserializeObject<JWT>(stringJWT);

            HttpContext.Session.SetString("token", jwt.Token);

            ViewBag.Message = "User logged in successfully!";

            return View("Index");
        
    

HomeController(没什么特别的,除了我在开始时添加了授权)

   [Authorize]
    public class HomeController : Controller
    
        private readonly ILogger<HomeController> _logger;

        public HomeController(ILogger<HomeController> logger)
        
            _logger = logger;
        
...

在我的 startup.cs 上

ConfigureServices 方法

            services.AddMemoryCache();
            services.AddSession();

            services.AddAuthentication(options => 
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            )
                .AddCookie(options =>
                
                    options.LoginPath = "/Account/Login/";
                   // options.AccessDeniedPath = "/Account/Forbidden/";
                );

并在配置方法中添加了一些方法

            app.UseSession();

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

不确定我缺少什么,我安装了以下软件包,不知道是否缺少一些。

Microsoft.AspNet.WebApi.Client Microsoft.AspNetCore.Authentication.OpenIDConnect System.IdentityModel.Tokens.Jwt

我必须说,仅当我将属性 [Authorize] 放在家庭控制器上时才会出现问题(没有尝试任何其他位置,但我感觉我缺少绑定授权属性和方案的东西,但我没有当然)。

【问题讨论】:

作为我的假设,HomeController 是一个 Web 应用程序,不是吗?您正在尝试从“/Token”中检索 JWT,然后将其保存到 Session 中。在客户端,您尝试在用户获得 JWT 令牌后访问 Home,对吗?。 是的,正确 因此您必须将此令牌保存到 Cookie 而不是 Session,因为您的身份验证方案是基于 Cookie 的。你可以喜欢这个代码github.com/onelogin/openid-connect-dotnet-core-sample/blob/…,让你清楚如何使用Cookie和OpenId。 如果我没记错的话,你是在'/Token'中做self-JWT,对吧?实际上,JWT 仅用于通过附加 Authorization Header 来执行 Web API。在基于 Web 的场景中,您应该通过调用 HttpContext.SignInAsync() 而不是 JWT 来使用基于 Cookie。但如果您仍想使用 JWT 和 Session,您可以更改 options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme 并使用此主题 docs.microsoft.com/en-us/aspnet/core/signalr/… 和 OnMessageReceived 事件在 Request.Session 中检索 jwt 令牌 你是正确的“令牌”返回一个生成的 JWT 令牌,我在 api 上使用授权时用于验证,是的,在客户端使用 cookie 进行验证是有意义的,我正在尝试了解您发送给我的内容,谢谢 【参考方案1】:

对于您的客户端,您的启动看起来不错。

您应该使用 HttpContext.SignInAsync() 并使用 Cookie 存储您的令牌,因为您的身份验证方案是基于 cookie 的。

因此,例如,在使用 JWT 时,通常您有与之关联的声明。您将需要这些声明来构建 ClaimsPrincipal 对象以便登录。请参阅下面的更新代码:

注意:切勿在异步方法上使用“.Result”。另外,请考虑使用 IHttpClientFactory 而不是自己直接创建 HttpClient。

        [HttpPost]
        [AutoValidateAntiforgeryToken]
        public async Task<IActionResult> Login(AuthenticatedUser user)
        
            // This section should be essentially removed. Use IHttpClientFactory 
            string baseUrl = "http://localhost:8080";
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(baseUrl);
            var contentType = new MediaTypeWithQualityHeaderValue("application/json");
            client.DefaultRequestHeaders.Accept.Add(contentType);

            string stringData = JsonConvert.SerializeObject(user);
            var contentData = new StringContent(stringData, System.Text.Encoding.UTF8, "application/json");

            HttpResponseMessage response = await client.PostAsync("/Token", contentData);
            if (response.IsSuccessStatusCode) 
            
                string stringJWT = await response.Content.ReadAsStringAsync();
                JWT jwt = JsonConvert.DeserializeObject<JWT>(stringJWT);

                var userIdentity = new ClaimsIdentity(token.Claims, CookieAuthenticationDefaults.AuthenticationScheme);
                var userPrincipal = new ClaimsPrincipal(userIdentity);

                // This line here fixes your main issue
                await HttpContext.SignInAsync(userPrincipal);

                HttpContext.Response.Cookies.Append("token", jwt.Token);

                 ViewBag.Message = "User logged in successfully!";
            

            return View("Index");
        
    

反序列化令牌的注意事项,您也可以使用它:

public JwtSecurityToken GetDecodedToken(string token)

   return new JwtSecurityTokenHandler( ).ReadJwtToken(token);

【讨论】:

以上是关于添加授权时缺少身份验证方案的主要内容,如果未能解决你的问题,请参考以下文章

HTTP 请求未经客户端身份验证方案“Ntlm”授权

摘要身份验证返回未经授权的

客户端身份验证方案“匿名”的 HTTP 请求未经授权?

您正在使用哪些身份验证和授权方案 - 为啥?

未经授权的客户端身份验证方案“匿名”和 URI 方案“https”无效;预期的“http”

HTTP 请求未经客户端身份验证方案“基本”授权。从服务器收到的身份验证标头为“基本领域 =”