代码之家  ›  专栏  ›  技术社区  ›  pStan

带jwt的core 2.0api auth返回未经授权的

  •  1
  • pStan  · 技术社区  · 8 年前

    我正在尝试将JWT的令牌身份验证添加到我的.NET Core 2.0应用程序中。我有一个简单的控制器,它返回要测试的用户列表。

    [Authorize]
    [Route("api/[controller]")]
    public class UsersController : Controller
    {
        ...
    
        [HttpGet]
        [Route("api/Users/GetUsers")]
        public IEnumerable<ApplicationUser> GetUsers()
        {
            return _userManager.Users;
        }
    
    
    }
    

    我有一个用于令牌安全的api控制器。它有一个返回令牌字符串结果的登录方法。

        [HttpPost(nameof(Login))]
        public async Task<IActionResult> Login([FromBody] LoginResource resource)
        {
            if (resource == null)
                return BadRequest("Login resource must be asssigned");
    
            var user = await _userManager.FindByEmailAsync(resource.Email);
    
            if (user == null || (!(await _signInManager.PasswordSignInAsync(user, resource.Password, false, false)).Succeeded))
                return BadRequest("Invalid credentials");
    
            string result = GenerateToken(user.UserName, resource.Email);
    
            // Token is created, we can sign out
            await _signInManager.SignOutAsync();
    
            return Ok(result);
        }
    
        private string GenerateToken(string username, string email)
        {
            var claims = new Claim[]
            {
                new Claim(ClaimTypes.Name, username),
                new Claim(ClaimTypes.Email, email),
                new Claim(JwtRegisteredClaimNames.Nbf, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString()),
                new Claim(JwtRegisteredClaimNames.Exp, new DateTimeOffset(DateTime.Now.AddDays(1)).ToUnixTimeSeconds().ToString()),
            };
    
            var token = new JwtSecurityToken(
                new JwtHeader(new SigningCredentials(
                    new SymmetricSecurityKey(Encoding.UTF8.GetBytes("the secret that needs to be at least 16 characeters long for HmacSha256")),
                                             SecurityAlgorithms.HmacSha256)),
                new JwtPayload(claims));
    
            return new JwtSecurityTokenHandler().WriteToken(token);
        }
    

    我有一个小的控制台应用程序只是用来测试API当我试图让用户使用jwt时。我马上收到一个“未经授权”的通知如果我从用户控制器中删除“[授权]”…成功似乎无法识别我的标题授权,但不确定原因。

        private static async Task<String> GetUsers(String jwt)
        {
            var url = "https://localhost:44300/";
            var apiUrl = $"/api/Users/";
    
            using (var client = new HttpClient() { BaseAddress = new Uri(url) })
            {
                client.BaseAddress = new Uri(url);
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwt}");
    
                using (var response = await client.GetAsync(apiUrl))
                {
                    if (response.StatusCode == System.Net.HttpStatusCode.OK)
                        return await response.Content.ReadAsStringAsync();
    
                    else return null;
                }
            }
        }
    

    我的尝试是基于这篇文章 here ... 其中一些可能有点过时。

    update-startup.cs的摘录

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = "Jwt";
                options.DefaultChallengeScheme = "Jwt";
            }).AddJwtBearer("Jwt", options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateAudience = false,
                    //ValidAudience = "the audience you want to validate",
                    ValidateIssuer = false,
                    //ValidIssuer = "the isser you want to validate",
    
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("the secret that needs to be at least 16 characeters long for HmacSha256")),
    
                    ValidateLifetime = true, //validate the expiration and not before values in the token
    
                    ClockSkew = TimeSpan.FromMinutes(5) //5 minute tolerance for the expiration date
                };
            });
    

    配置。。。

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
    
            app.UseStaticFiles();
    
            app.UseAuthentication();
    
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
    
            //app.UseJwtBearerAuthentication(
            //    new Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions
            //    );
    
    
        }
    

    解决方案:

    这一行正在转义令牌,因此在下一个请求中传递时使其无效:

    var result = await response.Content.ReadAsStringAsync();
    

    替换为:

    var result = await response.Content.ReadAsAsync<string>();
    

    注意:要使用这个ext方法,我必须“安装包Microsoft.AspNet.WebApi.Client”

    2 回复  |  直到 8 年前
        1
  •  4
  •   Celal Yildirim    8 年前

    我在我的一个项目中使用了JWT身份验证我想展示一下我的实现,也许这对你有帮助但你可能忘了加上 使用身份验证(); 在启动类中配置方法。

    启动.cs

        public void Configure(IApplicationBuilder app)
        {
            app.UseAuthentication();
            app.UseMvc();
        }
    
        public void ConfigureServices(IServiceCollection services)
        {
            var appSettings = Configuration.GetSection("AppSettings");
    
            services.AddAuthentication(options =>
                                       {
                                           options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                                           options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                                       }
                                      )
                    .AddJwtBearer(options =>
                    {
                        options.TokenValidationParameters = new TokenValidationParameters
                        {
                            ValidateAudience = true,
                            ValidAudience = appSettings["JwtAudience"],
                            ValidateIssuer = true,
                            ValidIssuer = appSettings["JwtIssuer"],
                            ValidateLifetime = true,
                            ValidateIssuerSigningKey = true,
                            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(appSettings["JwtSigningKey"]))
                        };
                    });
        }
    

    generateToken方法

        private string GenerateToken(string email)
        {
            SecurityKey securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.Value.JwtSigningKey));
    
            var token = new JwtSecurityToken(
                                             issuer: _appSettings.Value.JwtIssuer,
                                             audience: _appSettings.Value.JwtAudience,
                                             claims: new[]
                                             {
                                                 new Claim(JwtRegisteredClaimNames.UniqueName, email),
                                                 new Claim(JwtRegisteredClaimNames.Email, email),
                                                 new Claim(JwtRegisteredClaimNames.NameId, Guid.NewGuid().ToString())
                                             },
                                             expires: DateTime.Now.AddMinutes(_appSettings.Value.JwtExpireMinute),
                                             signingCredentials: new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256)
                                            );
    
            return new JwtSecurityTokenHandler().WriteToken(token);
        }
    
        2
  •  2
  •   Neville Nazerane    8 年前

    我创建了一个nuget包 NetCore.Jwt 最近简化了这个过程每次你需要一个Jwt时,我都觉得不值得写所有的代码,因为你只需要使用函数就可以处理cookies SignInAsync 是的。然而,如果您更喜欢手动方式,Celal的答案是这个过程的一个清晰而直接的指南。

    或者,您可以安装 NetCore.Jwt公司 在你的创业中使用以下方法:

    services.AddAuthentication(NetCoreJwtDefaults.SchemeName)
        .AddNetCoreJwt(options => 
            {
                // configure your token options such as secret, expiry, and issuer here
            });
    

    在你的 Login 函数,您可以使用扩展函数 HttpContext

    string token = HttpContext.GenerateBearerToken( new Claim[]
        {
            new Claim(ClaimTypes.Name, username),
            new Claim(ClaimTypes.Email, email),
            new Claim(JwtRegisteredClaimNames.Nbf, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString()),
            new Claim(JwtRegisteredClaimNames.Exp, new DateTimeOffset(DateTime.Now.AddDays(1)).ToUnixTimeSeconds().ToString()),
        });
    
    推荐文章