我正在使用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
};
});
答案 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)
};
});