NET Core 2中基于JWT的API授权:无未授权错误

时间:2019-03-14 20:35:00

标签: c# .net-core jwt asp.net-authorization

好吧,我正在尝试在.NET Core 2.x API中建立基于JWT的授权。除此以外,我一切正常,我已设置为应用授权的测试操作不是拒绝未经身份验证的请求,它只是提供内容,就像根本没有应用任何授权一样。

在我的Startup中,我有:

    services.AddAuthentication(authOptions =>
    {
        authOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        authOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(jwtOptions =>
    {
        jwtOptions.Authority = configuration["Jwt:Issuer"];
        jwtOptions.SaveToken = true;
        jwtOptions.RequireHttpsMetadata = false;
        jwtOptions.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidIssuer = configuration["Jwt:Issuer"],
            ValidAudience = configuration["Jwt:Issuer"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:Key"]))
        };
    });

    services.AddAuthorization(options =>
    {
        options.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
            .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
            .RequireAuthenticatedUser()
            .Build());
    });

然后在Configure中输入

app.UseAuthentication();

我有一个类似的登录API动作:

...
    [Route("api/user")]
    [ApiController]
    public class AppUserController : ControllerBase
    {
...
        [HttpPost("authenticate")]
        [AllowAnonymous]
        [Produces("application/json")]
        public async Task<IActionResult> Authenticate([FromBody] LoginDto model)
        {
            if (ModelState.IsValid)
            {
                var user = await _authenticationHandler.Authenticate(model);

                if (user != null)
                {
                    return Ok(_authenticationHandler.GetJwt(user.Name));
                }
            }

            ModelState.AddModelError("", "Invalid login attempt");

            return Ok();
        }
    }
...

_authenticationHandler是以下对象的实例

public class IdentityHandler
{
    private readonly UserManager<AppUser> _userManager;
    private readonly IConfiguration _configuration;

    public IdentityHandler
    (
        IConfiguration configuration,
        UserManager<AppUser> userManager
    )
    {
        _configuration = configuration;
        _userManager = userManager;
    }

    public string GetJwt(string username)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var claims = new HashSet<Claim>
        {
            new Claim(JwtRegisteredClaimNames.Sub, username),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim(JwtRegisteredClaimNames.Iat, DateTime.Now.ToString())
        };

        var token = new JwtSecurityToken
        (
            _configuration["Jwt:Issuer"], 
            claims: claims,
            signingCredentials: credentials,
            expires: DateTime.Now.AddDays(10)
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }

    public async Task<ClaimsIdentity> Authenticate(LoginDto loginModel)
    {
        var user = await _userManager.FindByNameAsync(loginModel.Username);
        var identity = new ClaimsIdentity();

        if (user != null && await _userManager.CheckPasswordAsync(user, loginModel.Password))
        {
            identity.AddClaim(new Claim(ClaimTypes.Name, user.NormalizedUserName));
        }

        return identity;
    }
}

最后,我然后用Authorize指令注释了一个API动作,例如:

[HttpGet("test")]
[Authorize]
[Produces("application/json")]
public IActionResult Test()
{
    return Ok("accepted");
}

我的期望是,如果我尝试导航至该操作,则该请求应被拒绝为未经授权。它不是。作为JWT的新手,我不知道自己错过了什么。

我可以确认我的登录方法确实有效,找到用户并签发令牌,该令牌会在客户端收到。

1 个答案:

答案 0 :(得分:0)

好吧,在启动类的ConfigureServices方法中进行了一些额外的探索之后,我找到了自己的问题的答案,有必要指定要添加到MVC的授权过滤器,例如所以:

    services.AddMvc(config =>
        config.Filters.Add(new AuthorizeFilter(JwtBearerDefaults.AuthenticationScheme))
    );

就是这样。我的带有[Authorize]批注的操作现在可以按预期拒绝匿名请求。