401即使在成功验证JWT令牌后也未经授权

时间:2019-05-23 12:57:03

标签: jwt asp.net-core-webapi asp.net-core-2.1 jwt-auth

我正在使用JWT令牌来保护我的.net核心api。我在登录时创建JWT令牌,并通过将该令牌传递到标头中使用该令牌来调用其他api。

我创建了一个自定义授权过滤器来验证我的令牌,并授予用户访问api的权限,并且授权过滤器正在成功验证我的令牌。

AccountController.cs代码:

[Authorize]
[AuthorizationFilter]
[Route("api/account")]
[ApiController]
public class AccountController : ControllerBase
{
    public IConfiguration _configuration { get; }
    ResponseModel rs = null;
    private readonly JWTSettings _jwtSettings;

    public AccountController(IOptions<JWTSettings> jwtSettings, IConfiguration configuration)
    {
        _jwtSettings = jwtSettings.Value;
        _configuration = configuration;
    }

    [AllowAnonymous]
    [HttpPost]
    [Route("signin")]
    public IActionResult SignIn([FromBody]LoginRequest data)
    {
        try
        {
            AppConfiguration appConfig = new AppConfiguration(_configuration);
            string constring = appConfig.GetConnectionString(data.CLIENTID);

            if(constring != null)
            {
                rs = new ResponseModel();
                AccountDL objAccountDL = new AccountDL(_configuration);
                rs = objAccountDL.SignIn(data);

                if (rs == null)
                    return BadRequest(new { message = "Username or password is incorrect" });

                var tokenHandler = new JwtSecurityTokenHandler();
                var key = Encoding.ASCII.GetBytes(_jwtSettings.SECRET);
                var currentTime = DateTime.Now;
                var expires = DateTime.Now.AddMinutes(15);

                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    //Expires = DateTime.UtcNow.AddDays(7),
                    Expires = expires,
                    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
                };
                var token = tokenHandler.CreateToken(tokenDescriptor);
                var tokenString = tokenHandler.WriteToken(token);
                rs.Token = tokenString;

                // return basic user info (without password) and token to store client side
                return Ok(rs);
            }
            else
            {
                return Ok(new ResponseModel { StatusCode = 0, StatusDescription = "Error", ResultSet = "Client ID is not valid", ReasonPhrase = null });
            }
        }
        catch (Exception ex)
        {
            return Content(HttpStatusCode.InternalServerError.ToString(), new ResponseModel { StatusCode = 0, StatusDescription = "Error", ResultSet = null, ReasonPhrase = ex.Message }.ToString());
        }
        finally
        {
            rs = null;
        }
    }

    //[AllowAnonymous]
    [HttpPost]
    [Route("getmenu")]
    public IActionResult GetMenu([FromBody]MenuRequest data)
    {
        try
        {
            rs = new ResponseModel();
            AccountDL objAccountDL = new AccountDL(_configuration);
            rs = objAccountDL.GetMenu(data);
            return Ok(rs);
        }
        catch (Exception ex)
        {
            return Content(HttpStatusCode.InternalServerError.ToString(), new ResponseModel { StatusCode = 0, StatusDescription = "Error", ResultSet = null, ReasonPhrase = ex.Message }.ToString());
        }
        finally
        {
            rs = null;
        }
    }
}

AuthorizationFilter.cs代码:

public class AuthorizationFilter : AuthorizeAttribute, IAuthorizationFilter
{
    public string secretkey = "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING";

    public void OnAuthorization(AuthorizationFilterContext filterContext)
    {
        if (!ValidateToken(filterContext.HttpContext.Request.Headers["TOKEN"]))
        {
            filterContext.Result = new UnauthorizedResult();
        }
    }

    private bool ValidateToken(string authToken)
    {
        try
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var validationParameters = GetValidationParameters();

            SecurityToken validatedToken;
            IPrincipal principal = tokenHandler.ValidateToken(authToken, validationParameters, out validatedToken);
            return true;
        }
        catch(Exception ex)
        {
            return false;
        }
    }

    private TokenValidationParameters GetValidationParameters()
    {
        return new TokenValidationParameters()
        {
            ValidateLifetime = false, // Because there is expiration in the generated token
            ValidateAudience = false, // Because there is no audiance in the generated token
            ValidateIssuer = false,   // Because there is no issuer in the generated token
            //ValidIssuer = _appSettings.ValidIssuer,
            //ValidAudience = _appSettings.ValidAudience,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretkey)) // The same key as the one that generate the token
        };
    }
}

我不希望任何匿名用户访问我的api,因此我从AccountController.cs中的getmenu api中注释了[AllowAnonymous]属性,但这给了我

  

“ 401未经授权”

即使成功验证了令牌后,在注释[AllowAnonymous]后出现

错误,但是如果我在api上使用[AllowAnonymous]属性,则它可以正确地命中api。 可能是什么问题?

更新:

var jwtSettings = jwtSettingsSection.Get<JWTSettings>();
var key = Encoding.ASCII.GetBytes(jwtSettings.SECRET);
services.AddAuthentication(x =>
{
    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
    x.RequireHttpsMetadata = false;
    x.SaveToken = true;
    x.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = false,
        ValidateAudience = false,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(key),
        ClockSkew = TimeSpan.Zero
    };
});

1 个答案:

答案 0 :(得分:0)

您需要从验证令牌的开头删除“ Bearer”一词。

当您要调用api时,需要将此字符串添加到授权标头:“ Bearer XXX”。

当您要使用和解析令牌时,需要从授权标头的开头删除“承载者”,并准确地解析XXX的值而没有任何前缀。

private bool ValidateToken(string authToken)
    {
        try
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var validationParameters = GetValidationParameters();
            SecurityToken validatedToken;

            var jwt = authToken.Replace("Bearer ", string.Empty);

            IPrincipal principal = tokenHandler.ValidateToken(jwt, validationParameters, out validatedToken);
            return true;
        }
        catch (Exception ex)
        {
            return false;
        }
    }

更新:

我的ConfigureService(使用您自己的密钥替换):

 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            var x = Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]);
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = Configuration["Jwt:Issuer"],
                ValidAudience = Configuration["Jwt:Issuer"],
                IssuerSigningKey = new SymmetricSecurityKey(x)
            };
        });