本文章参考了其他朋友的博客,但是我确实不知道参考的谁了,所以自己记录一下,防止忘记。
首先创建了一个ApiAuthorizedByJWT类库·,具体内容如下(四部分分别是 生成的jwt类,角色权限对应关系,jwt验证方法,许可要求类):
1 using Microsoft.AspNetCore.Mvc; 2 using System; 3 using System.IdentityModel.Tokens.Jwt; 4 using System.Security.Claims; 5 6 namespace ApiAuthorizedByJWT 7 { 8 public class JWTAuthorizeCLASS 9 {10 public bool Status;11 public string access_token;12 public double expires_in;13 public string token_type;14 public static dynamic BuildOwnToken(Claim[] claims, PermissionRequirement permissionRequirement)15 {16 var now = DateTime.UtcNow;17 var jwt = new JwtSecurityToken(18 issuer: permissionRequirement.Issuer,19 audience: permissionRequirement.Audience,20 claims: claims,21 notBefore: now,22 expires: now.Add(permissionRequirement.Expiration),23 signingCredentials: permissionRequirement.SigningCredentials24 );25 var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);26 JWTAuthorizeCLASS rtres = new JWTAuthorizeCLASS27 {28 Status = true,29 access_token = encodedJwt,30 expires_in = permissionRequirement.Expiration.TotalMilliseconds,31 token_type = "Bearer"32 };33 34 35 return rtres;36 }37 }38 }
using System;using System.Collections.Generic;using System.Text;namespace ApiAuthorizedByJWT{ ////// 角色与权限url对应的类 /// public class Permission { ////// 角色名称 /// public virtual string RoleName { get; set; } ////// 链接地址 /// public virtual string Url { get; set; } } }
using Microsoft.AspNetCore.Authentication;using Microsoft.AspNetCore.Authorization;using Microsoft.Extensions.DependencyInjection;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;////// 这里必须注意:此处引用了nuget包:Microsoft.AspNetCore.Mvc.Abstractions;否则这个Microsoft.AspNetCore.Mvc不存在 以及Microsoft.AspNetCore.All/// namespace ApiAuthorizedByJWT{ public class PermissionHandler : AuthorizationHandler{ /// /// 验证方案提供对象 /// public IAuthenticationSchemeProvider Schemes { get; set; } ////// 自定义策略参数 /// public PermissionRequirement Requirement { get; set; } ////// 构造 /// /// public PermissionHandler(IAuthenticationSchemeProvider schemes) { Schemes = schemes; } protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) { ////赋值用户权限 Requirement = requirement; //从AuthorizationHandlerContext转成HttpContext,以便取出表求信息 var httpContext = (context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext).HttpContext; //请求Url var questUrl = httpContext.Request.Path.Value.ToLower(); //判断请求是否停止 var handlers = httpContext.RequestServices.GetRequiredService(); foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync()) { var handler = await handlers.GetHandlerAsync(httpContext, scheme.Name) as IAuthenticationRequestHandler; if (handler != null && await handler.HandleRequestAsync()) { context.Fail(); return; } } //判断请求是否拥有凭据,即有没有登录 var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync(); if (defaultAuthenticate != null) { var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name); //result?.Principal不为空即登录成功 if (result?.Principal != null) { httpContext.User = result.Principal; //权限中是否存在请求的url if (Requirement.Permissions.GroupBy(g => g.Url).Where(w => w.Key.ToLower() == questUrl).Count() > 0) { var name = httpContext.User.Claims.SingleOrDefault(s => s.Type == requirement.ClaimType).Value; //验证权限 if (Requirement.Permissions.Where(w => w.RoleName == name && w.Url.ToLower() == questUrl).Count() <= 0) { context.Fail(); return; } context.Succeed(requirement); } return; //var userroles = requirement.Permissions; } } if (!questUrl.Equals(Requirement.LoginPath.ToLower(), StringComparison.Ordinal) && (!httpContext.Request.Method.Equals("POST") || !httpContext.Request.HasFormContentType)) { context.Fail(); return; } context.Succeed(requirement); } }}
using Microsoft.AspNetCore.Authorization;using Microsoft.IdentityModel.Tokens;using System;using System.Collections.Generic;using System.Text;namespace ApiAuthorizedByJWT{ ////// 许可要求 /// public class PermissionRequirement:IAuthorizationRequirement { ////// 用户权限集合 /// public ListPermissions { get; private set; } /// /// 无权限action /// public string DeniedAction { get; set; } = "/Api/ReLogin"; ////// 认证授权类型 /// public string ClaimType { internal get; set; } ////// 请求路径 /// public string LoginPath { get; set; } = "/Api/Login"; ////// 发行人 /// public string Issuer { get; set; } ////// 订阅人 /// public string Audience { get; set; } ////// 过期时间 /// public TimeSpan Expiration { get; set; } = TimeSpan.FromMinutes(60); ////// 签名验证 /// public SigningCredentials SigningCredentials { get; set; } ////// 构造 /// /// 拒约请求的url /// 权限集合 /// 声明类型 /// 发行人 /// 订阅人 /// 签名验证实体 public PermissionRequirement(string deniedAction, Listpermissions, string claimType, string issuer, string audience, SigningCredentials signingCredentials) { ClaimType = claimType; DeniedAction = deniedAction; Permissions = permissions; Issuer = issuer; Audience = audience; SigningCredentials = signingCredentials; } }}
那么在真正的使用中,要在core中添加上对应的一些数据信息。首先常见一个关于登录用户的类
using ApiAuthorizedByJWT;using Dapper;using Microsoft.Extensions.Options;using Microsoft.IdentityModel.Tokens;using new_m1_1_0.Models.interfaces;using System;using System.Collections.Generic;using System.Data;using System.Linq;using System.Security.Claims;using System.Text;using System.Threading.Tasks;namespace new_m1_1_0.Models.models{ public class LoginUser:ILoginUser { public string Username; public string UserID; public string Accid; public string Password; public string Acctoken; public ListLRC; public JWTAuthorizeCLASS apitoken; private bool isInit = false; public LoginUser(string ID,string Key,Func CheckMethed, string connectstring) { //--------------------校验方法-------------------------------- //pass if (CheckMethed(ID, Key, connectstring)) { Password = Key; IDbConnection conn = new MySql.Data.MySqlClient.MySqlConnection(connectstring); string sql1 = "select a.user_name,a.role_key,b.name,b.remark,c.url,c.name as func_name,c.sourse,d.resource_key,e.source_name from m1_user_roles a,m1_role b,m1_resource c,m1_permission d,m1_sourse e where a.user_name = @ID and b.role_key = a.role_key and d.role_key = a.role_key and c.resource_key = d.resource_key and e.source_key = c.sourse and e.role_key = a.role_key"; List loginUserInfo = conn.Query (sql1, new { id = ID }).ToList(); string sql2 = "select a.user_name,a.accid,a.acctoken,b.nick_name from m1_user_im a,m1_user b where a.user_name = @id and b.user_name = a.user_name"; List < LoginUserNeteaseInfo> loginUserNeteaseInfo = conn.Query (sql2, new { id = ID }).ToList(); LRC = new List (); List sourseL = new List (); for (int i = 0; i < loginUserInfo.Count; i++) { if (!sourseL.Contains(loginUserInfo[i].sourse)) { sourseL.Add(loginUserInfo[i].sourse); SourceWithRole sourceWithRole = new SourceWithRole(); sourceWithRole.L = new List (); var rwc = new RoleWithCode(); rwc.Code = loginUserInfo[i].resource_key; rwc.RoleName = loginUserInfo[i].name; rwc.RoleKey = loginUserInfo[i].role_key; rwc.Url = loginUserInfo[i].url; sourceWithRole.L.Add(rwc); sourceWithRole.SourceCode = loginUserInfo[i].sourse; sourceWithRole.SourceName = loginUserInfo[i].source_name; LRC.Add(sourceWithRole); } else { for (int j = 0; j < LRC.Count; j++) { if (LRC[j].SourceCode == loginUserInfo[i].sourse) { var rwc = new RoleWithCode(); rwc.Code = loginUserInfo[i].resource_key; rwc.RoleName = loginUserInfo[i].name; rwc.RoleKey = loginUserInfo[i].role_key; rwc.Url = loginUserInfo[i].url; LRC[j].L.Add(rwc); } else { continue; } } } } try { Username = loginUserNeteaseInfo[0].nick_name; Accid = loginUserNeteaseInfo[0].accid; Acctoken = loginUserNeteaseInfo[0].acctoken; UserID = loginUserNeteaseInfo[0].user_name; this.apitoken = GetLoginUserToken(); } catch (Exception ex) { Username = ""; Accid = ""; Acctoken = ""; UserID = ""; LRC = null; } } else { Username = ""; UserID = ""; Password = ""; Accid = ""; Acctoken = ""; LRC = null; } } public JWTAuthorizeCLASS GetLoginUserToken() { if (LRC == null || LRC.Count < 1) { return null; } var symmetricKeyAsBase64 = "TTT11111TTT111TTTTT11TTTTTT11111111111";//audienceConfig["Secret"]; var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); var signingKey = new SymmetricSecurityKey(keyByteArray); var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256); int apicount = 0; List roles = new List (); var permission = new List (); for (int i = 0; i < LRC.Count; i++) { for (int j = 0; j < LRC[i].L.Count; j++) { if (roles.Contains(LRC[i].L[j].RoleKey)) { } else { roles.Add(LRC[i].L[j].RoleKey); } permission.Add(new Permission { Url = LRC[i].L[j].Url,RoleName= LRC[i].L[j].RoleKey}); } } List claimArray = new List (); for (int i = 0; i < roles.Count; i++) { claimArray.Add(new Claim(ClaimTypes.Role, roles[i])); } claimArray.Add(new Claim(ClaimTypes.Name, UserID)); return JWTAuthorizeCLASS.BuildOwnToken(claimArray.ToArray(), new PermissionRequirement("/api/login", permission, ClaimTypes.Role, "lsnct", "everyone", signingCredentials)); } } public class RoleWithCode { /// /// 角色名称 /// public string RoleName; ////// 权限code /// public string Code; ////// 链接 /// public string Url; ////// 角色关键字 /// public string RoleKey; } public class SourceWithRole { ////// 资源模块代码 /// public string SourceCode; ////// 资源模块名称 /// public string SourceName; ////// 所属角色与api列表 /// public ListL; }}
然后在控制器中处理
[HttpPost] public JsonResult Post() { var username = HttpContext.Request.Form["username"].ToString().Trim();//获取 var pwd = HttpContext.Request.Form["pwd"].ToString().Trim(); LoginUser LU = new LoginUser(username,pwd,CheckLogin.checkmethed1, appSettings.dbcc_sys); LU.Password = ""; return new JsonResult(LU); }
生成了token后,后面会拿这个token访问接口。
在对应的工程的startup.cs中处理
var symmetricKeyAsBase64 = "TTT11111TTT111TTTTT11TTTTTT11111111111";//audienceConfig["Secret"]; var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); var signingKey = new SymmetricSecurityKey(keyByteArray); var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = signingKey, ValidateIssuer = true, ValidIssuer = "lsnct", //audienceConfig["Issuer"], ValidateAudience = true, ValidAudience = "everyone", //audienceConfig["Audience"], ValidateLifetime = true, ClockSkew = TimeSpan.Zero }; var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256); services.AddAuthorization(options => { //var permission = GetAllPermission(); Listpermission = null; if (permission == null) { //这个集合模拟用户权限表,可从数据库中查询出来 permission = new List { new Permission { Url="/api/getValues1", RoleName="system"}, new Permission { Url="/api/values/getValues1", RoleName="admin"}, new Permission{ Url="/api/getValues3", RoleName="admin"}, new Permission{ Url="/api/Products/GetMomentDetails", RoleName="system"} }; } //如果第三个参数,是ClaimTypes.Role,上面集合的每个元素的Name为角色名称,如果ClaimTypes.Name,即上面集合的每个元素的Name为用户名 //var permissionRequirement = new PermissionRequirement("/api/denied", permission, ClaimTypes.Role, audienceConfig["Issuer"], audienceConfig["Audience"], signingCredentials); var permissionRequirement = new PermissionRequirement("/Api/Login", permission, ClaimTypes.Role, "lsnct", "everyone", signingCredentials); options.AddPolicy("Permission", policy => policy.Requirements.Add(permissionRequirement)); }).AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(o => { //不使用https o.RequireHttpsMetadata = false; o.TokenValidationParameters = tokenValidationParameters; }); //注入授权Handler services.AddSingleton (); services.AddMvc() .AddJsonOptions(options=> { options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;//忽略循环引用 options.SerializerSettings.ContractResolver = new DefaultContractResolver();//不使用驼峰样式key options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";//时间格式化 });
最后在对应接口加上[Authorize("Permission")]标记即可。