带有 JWT 的 Core 2.0 API Auth 返回未经授权 [英] Core 2.0 API Auth with JWT returns unauthorized

查看:21
本文介绍了带有 JWT 的 Core 2.0 API Auth 返回未经授权的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to add Token Authentication with JWT to my .Net Core 2.0 app. I have a simple controller that returns a list of users for testing.

[Authorize]
[Route("api/[controller]")]
public class UsersController : Controller
{
    ...

    [HttpGet]
    [Route("api/Users/GetUsers")]
    public IEnumerable<ApplicationUser> GetUsers()
    {
        return _userManager.Users;
    }


}

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

I have an API Controller for Token security. It has a login method which returns a Token string result.

    [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 获取用户时.我立即收到未经授权".如果我从用户控制器中删除[授权]"...成功.似乎无法识别我的标头授权,但不知道为什么.

I have a small console app just for testing the API. When I attempt to Get the Users using the jwt. I receive an immediate "unauthorized". If I remove the "[Authorize]" from the users Controller... success. It appears that my header Authorization is not recognized, but not sure why.

    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;
            }
        }
    }

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

I'm basing my attempts on the article here ... some of which might be slightly out of date.

更新 - 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
        //    );


    }

解决方案:

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

This line was escaping the token therefore causing it to be invalid when passed in the next request:

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

替换为:

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

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

Note: To use this ext method I had to "install-package Microsoft.AspNet.WebApi.Client"

推荐答案

我在我的一个项目中使用了 JWT 身份验证.我想展示我的实现,也许这会对你有所帮助.但是你可能忘记在启动类的 configure 方法中添加 UseAuthentication(); .

I used JWT authentication in my one of project. I would like to show my implementation, maybe this will help you. But probably you forget to add UseAuthentication(); into configure method in startup class.

startup.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);
    }

这篇关于带有 JWT 的 Core 2.0 API Auth 返回未经授权的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆