提问者:小点点

在请求标头中输入JWT令牌时,自定义授权属性无法工作


[ASP.NET中的一个简单Web API]

当我发送没有JWT令牌的请求时,代码会给出401未经授权的响应。到目前为止一切看起来都很好。

当我在代码中输入由 generateJWT() 方法生成的 JWT 令牌以对用户进行身份验证时,请求结束而没有到达自定义授权属性和控制器。

这是自定义授权属性:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizeAttribute : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var user = (User)context.HttpContext.Items["User"];

        if (user == null)
        {
            context.Result = new JsonResult(new { message = "unauthorized" }) { StatusCode = StatusCodes.Status401Unauthorized };
        }
    }
}

当我没有在请求头中添加jwt标记时,请求到达这里并给出401响应。

使用 jwt 令牌,请求不会到达此处。它以自定义 JwtMiddleware 结束,尽管就我而言,它运行良好,验证令牌并找到用户:

public class JwtMiddleware
{
    private readonly RequestDelegate _next;
    private readonly AppSettings _appSettings;

    public JwtMiddleware(RequestDelegate next, IOptions<AppSettings> appSettings)
    {
        _next = next;
        _appSettings = appSettings.Value;
    }

    public async Task Invoke(HttpContext context, IUserService userService)
    {
        var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();

        if (token == null) await _next(context);

        attachUserToContext(context, userService, token);
    }

    private void attachUserToContext(HttpContext context, IUserService userService, string token)
    {
        try
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_appSettings.Secret);

            tokenHandler.ValidateToken(token, new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false,
                ClockSkew = TimeSpan.Zero
            }, out SecurityToken validatedToken);

            var jwtToken = (JwtSecurityToken)validatedToken;
            var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value);

            context.Items["User"] = userService.GetById(userId);
        }

        catch
        {
            // do nothing
        }


    }
}

你能发现这里发生了什么吗?


共1个答案

匿名用户

在中间件中,看起来只有在没有提供令牌的情况下才会调用RequestDelegate:<code>if(token==null)wait _next(context)

如果有令牌,则会运行 attachUserToContext 方法,但不调用 _next(context),因此管道的其余部分不会被执行(这是 mvc 管道与自定义属性一起的位置)。

来自文档:请求管道中的每个中间件组件负责调用管道中的下一个组件或使管道短路。

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-3.1

因此,我们应该更改逻辑,使其始终调用_next

var token = ...

if (token != null)
    attachUserToContext(context, userService, token);

await _next(context);

另一种可能的选择是,如果没有提供令牌,则通过将401状态代码写入conttext. Response而不调用_next来短路管道。