.net core 使用 System.IdentityModel.Tokens.Jwt 来实现JWT 鉴权。
可自定义鉴权失败的出参。支持Swagger验证
话不多说,直接上码
第一步: JWT实现servic:DiJWTServiceCollectionExtensions///第二步:自定义过滤器 MyAuthorizeFilter/// jwt 用户权限 /// public static class JwtRole { ////// 用户登录的 /// public const string UserInfo = "UserInfo"; ////// 设备登录的 /// public const string DeviceInfo = "DeviceInfo"; } ////// 微软 System.IdentityModel.Tokens.Jwt /// public class JwtService { private TokenValidationParameters _tokenValidationParameters { get; set; } ////// /// /// public JwtService(TokenValidationParameters tokenValidationParameters) { _tokenValidationParameters = tokenValidationParameters; } ////// 生产JWTToken /// /// /// /// 过期时间 ///public string GenerateJwtToken(Claim claim, string role, DateTime expires) { var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new Claim[] { claim, new Claim(ClaimTypes.Role,role) }), Expires = expires, SigningCredentials = new SigningCredentials(_tokenValidationParameters.IssuerSigningKey, SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); } /// /// 验证token是否合理,返回对应的值 /// /// /// ///public bool ValidatedJwtToken(string authenticationToken, out ClaimsPrincipal user) { bool result = false; user = null; try { if (string.IsNullOrEmpty(authenticationToken)) { return false; } //校验并解析token var handler = new JwtSecurityTokenHandler(); var claimsPrincipal = handler.ValidateToken(authenticationToken, _tokenValidationParameters, out SecurityToken validatedToken);//validatedToken:解密后的对象 //user = ((JwtSecurityToken)validatedToken).Payload.SerializeToJson(); //获取payload中的数据 result = claimsPrincipal.Identity.IsAuthenticated; user = claimsPrincipal; } catch (SecurityTokenExpiredException stee) { //表示过期 } catch (SecurityTokenException ste) { //表示token错误 } catch (Exception e) { } return result; } /// /// /// /// /// ///public bool ValidatedJwtToken(string authenticationToken, out object payload) { bool result = false; payload = null; try { if (string.IsNullOrEmpty(authenticationToken)) { return false; } //校验并解析token var handler = new JwtSecurityTokenHandler(); var claimsPrincipal = handler.ValidateToken(authenticationToken, _tokenValidationParameters, out SecurityToken validatedToken);//validatedToken:解密后的对象 //user = ((JwtSecurityToken)validatedToken).Payload.SerializeToJson(); //获取payload中的数据 result = claimsPrincipal.Identity.IsAuthenticated; var jwtVT = ((JwtSecurityToken)validatedToken); payload = jwtVT.Payload.GetValueOrDefault(ClaimTypes.Authentication) ?? jwtVT.Payload.GetValueOrDefault(ClaimTypes.UserData); } catch (SecurityTokenExpiredException stee) { //表示过期 Console.WriteLine("Token过期"); } catch (SecurityTokenException ste) { //表示token错误 Console.WriteLine("Token错误"); } catch (Exception e) { } return result; } } public static class DiJWTServiceCollectionExtensions { /// /// /// /// ///public static IServiceCollection AddJwtService(this IServiceCollection services,string serkey) { var tokenValidationParameters = new TokenValidationParameters() { ValidateIssuer = false,//是否验证Issuer ValidIssuer = "ApiServer", ValidateAudience = false,//是否验证Audience ValidateLifetime = true,//是否验证失效时间 ClockSkew = TimeSpan.FromSeconds(60), ValidateIssuerSigningKey = true,//是否验证SecurityKey //ValidAudience = Const.Domain,//Audience IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(serkey))//拿到SecurityKey }; //将此配置 注入服务,因为还有其他地方需要使用 services.AddSingleton(tokenValidationParameters); //注册 自定义服务 services.AddSingleton (); return services; } }
可自定义Headers,Query,cookies,token的入参名称:如下代码
var token = context.HttpContext.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last()
?? context.HttpContext.Request.Headers["X-Token"].FirstOrDefault()
?? context.HttpContext.Request.Query["Token"].FirstOrDefault()
?? context.HttpContext.Request.Cookies["Token"];
当然大家可随意设置,只需要和前端约定好即可。
///第三步:Startup 使用 第四步:添加OAuthController.cs 获取token 方法,以及测试方法/// 只为重写 OnAuthorizationAsync 自定义返回数据消息 /// public class MyAuthorizeFilter : IAsyncAuthorizationFilter { private JwtService _jwtService { get; set; } ////// /// /// public MyAuthorizeFilter(JwtService jwtService) { _jwtService = jwtService; } private static bool HasAllowAnonymous(AuthorizationFilterContext context) { var filters = context.Filters; for (var i = 0; i < filters.Count; i++) { if (filters[i] is IAllowAnonymousFilter) { return true; } } // When doing endpoint routing, MVC does not add AllowAnonymousFilters for AllowAnonymousAttributes that // were discovered on controllers and actions. To maintain compat with 2.x, // we'll check for the presence of IAllowAnonymous in endpoint metadata. var endpoint = context.HttpContext.GetEndpoint(); if (endpoint?.Metadata?.GetMetadata() != null) { return true; } return false; } /// /// /// /// ///public virtual async Task OnAuthorizationAsync(AuthorizationFilterContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (!context.IsEffectivePolicy(this)) { return; } // Allow Anonymous skips all authorization if (HasAllowAnonymous(context)) { return; } else { var token = context.HttpContext.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last() ?? context.HttpContext.Request.Headers["X-Token"].FirstOrDefault() ?? context.HttpContext.Request.Query["Token"].FirstOrDefault() ?? context.HttpContext.Request.Cookies["Token"]; ClaimsPrincipal user = context.HttpContext.User; if (_jwtService.ValidatedJwtToken(token, out user)) { //验证通过,验证成功 赋值给User context.HttpContext.User = user; } else { context.Result = new JsonResult(new { Code = 401, Message = "没有权限" }); } } //Console.WriteLine(JsonHelper.SerializeObject(context.HttpContext.Items)); } }
展示效果:
没有token 之前,调用Get接口 提示无权限。
为自定义出参哦,可以和自己项目整体出参自定义一致。
{
"code": 401,
"message": "没有权限"
}
获取token
点击下图所示第一步:将上图token填入文本框中。点击绿色按钮,最后点击close按钮。
重新执行get方法,就得到我们想要的了。
源码地址:https://github.com/BigMaJx/OOPDemo/blob/master/Api/Controllers/OAuthController.cs
https://github.com/BigMaJx/OOPDemo/blob/master/Api/SecuritysDI/



