本文章参考了其他朋友的博客,但是我确实不知道参考的谁了,所以自己记录一下,防止忘记。
首先创建了一个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.SigningCredentials
24 );
25 var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
26 JWTAuthorizeCLASS rtres = new JWTAuthorizeCLASS
27 {
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
{
/// <summary>
/// 角色与权限url对应的类
/// </summary>
public class Permission
{
/// <summary>
/// 角色名称
/// </summary>
public virtual string RoleName { get; set; }
/// <summary>
/// 链接地址
/// </summary>
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;
/// <summary>
/// 这里必须注意:此处引用了nuget包:Microsoft.AspNetCore.Mvc.Abstractions;否则这个Microsoft.AspNetCore.Mvc不存在 以及Microsoft.AspNetCore.All
/// </summary>
namespace ApiAuthorizedByJWT
{
public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
{
/// <summary>
/// 验证方案提供对象
/// </summary>
public IAuthenticationSchemeProvider Schemes { get; set; }
/// <summary>
/// 自定义策略参数
/// </summary>
public PermissionRequirement Requirement
{ get; set; }
/// <summary>
/// 构造
/// </summary>
/// <param name="schemes"></param>
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<IAuthenticationHandlerProvider>();
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
{
/// <summary>
/// 许可要求
/// </summary>
public class PermissionRequirement:IAuthorizationRequirement
{
/// <summary>
/// 用户权限集合
/// </summary>
public List<Permission> Permissions { get; private set; }
/// <summary>
/// 无权限action
/// </summary>
public string DeniedAction { get; set; } = "/Api/ReLogin";
/// <summary>
/// 认证授权类型
/// </summary>
public string ClaimType { internal get; set; }
/// <summary>
/// 请求路径
/// </summary>
public string LoginPath { get; set; } = "/Api/Login";
/// <summary>
/// 发行人
/// </summary>
public string Issuer { get; set; }
/// <summary>
/// 订阅人
/// </summary>
public string Audience { get; set; }
/// <summary>
/// 过期时间
/// </summary>
public TimeSpan Expiration { get; set; } = TimeSpan.FromMinutes(60);
/// <summary>
/// 签名验证
/// </summary>
public SigningCredentials SigningCredentials { get; set; }
/// <summary>
/// 构造
/// </summary>
/// <param name="deniedAction">拒约请求的url</param>
/// <param name="permissions">权限集合</param>
/// <param name="claimType">声明类型</param>
/// <param name="issuer">发行人</param>
/// <param name="audience">订阅人</param>
/// <param name="signingCredentials">签名验证实体</param>
public PermissionRequirement(string deniedAction, List<Permission> permissions, 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 List<SourceWithRole> LRC;
public JWTAuthorizeCLASS apitoken;
private bool isInit = false;
public LoginUser(string ID,string Key,Func<string,string,string,bool> 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> loginUserInfo = conn.Query<LoginUserInfo>(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<LoginUserNeteaseInfo>(sql2, new { id = ID }).ToList();
LRC = new List<SourceWithRole>();
List<string> sourseL = new List<string>();
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<RoleWithCode>();
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<string> roles = new List<string>();
var permission = new List<Permission>();
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<System.Security.Claims.Claim> claimArray = new List<Claim>();
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
{
/// <summary>
/// 角色名称
/// </summary>
public string RoleName;
/// <summary>
/// 权限code
/// </summary>
public string Code;
/// <summary>
/// 链接
/// </summary>
public string Url;
/// <summary>
/// 角色关键字
/// </summary>
public string RoleKey;
}
public class SourceWithRole
{
/// <summary>
/// 资源模块代码
/// </summary>
public string SourceCode;
/// <summary>
/// 资源模块名称
/// </summary>
public string SourceName;
/// <summary>
/// 所属角色与api列表
/// </summary>
public List<RoleWithCode> L;
}
}
然后在控制器中处理
[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();
List<Permission> permission = null;
if (permission == null)
{
//这个集合模拟用户权限表,可从数据库中查询出来
permission = new List<Permission> {
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<IAuthorizationHandler, PermissionHandler>();
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")]标记即可。
转载于:https://www.cnblogs.com/lsnct/p/8474229.html