mirror of
http://git.coreshop.cn/jianweie/coreshoppro.git
synced 2025-12-06 18:23:25 +08:00
添加项目文件。
This commit is contained in:
246
CoreCms.Net.Auth/AuthorizationSetup.cs
Normal file
246
CoreCms.Net.Auth/AuthorizationSetup.cs
Normal file
@@ -0,0 +1,246 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.Auth.Policys;
|
||||
using CoreCms.Net.Configuration;
|
||||
using CoreCms.Net.Utility.Extensions;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace CoreCms.Net.Auth
|
||||
{
|
||||
/// <summary>
|
||||
/// Db 启动服务
|
||||
/// </summary>
|
||||
public static class AuthorizationSetup
|
||||
{
|
||||
/// <summary>
|
||||
/// 后台管理员jwt初始化设置
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public static void AddAuthorizationSetupForAdmin(this IServiceCollection services)
|
||||
{
|
||||
if (services == null) throw new ArgumentNullException(nameof(services));
|
||||
|
||||
#region 参数
|
||||
//读取配置文件
|
||||
var symmetricKeyAsBase64 = AppSettingsConstVars.JwtConfigSecretKey;
|
||||
var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
|
||||
var signingKey = new SymmetricSecurityKey(keyByteArray);
|
||||
var issuer = AppSettingsConstVars.JwtConfigIssuer;
|
||||
var audience = AppSettingsConstVars.JwtConfigAudience;
|
||||
|
||||
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
// 如果要数据库动态绑定,这里先留个空,后边处理器里动态赋值
|
||||
var permission = new List<PermissionItem>();
|
||||
|
||||
// 角色与接口的权限要求参数
|
||||
var permissionRequirement = new PermissionRequirement(
|
||||
"/api/denied",// 拒绝授权的跳转地址(目前无用)
|
||||
permission,
|
||||
ClaimTypes.Role,//基于角色的授权
|
||||
issuer,//发行人
|
||||
audience,//听众
|
||||
signingCredentials,//签名凭据
|
||||
expiration: TimeSpan.FromSeconds(60 * 60 * 24)//接口的过期时间
|
||||
);
|
||||
#endregion
|
||||
|
||||
// 复杂的策略授权
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy(Permissions.Name,
|
||||
policy => policy.Requirements.Add(permissionRequirement));
|
||||
});
|
||||
|
||||
|
||||
// 令牌验证参数
|
||||
var tokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true, //是否验证SecurityKey
|
||||
IssuerSigningKey = signingKey, //拿到SecurityKey
|
||||
ValidateIssuer = true, //是否验证Issuer
|
||||
ValidIssuer = issuer,//发行人 //Issuer,这两项和前面签发jwt的设置一致
|
||||
ValidateAudience = true, //是否验证Audience
|
||||
ValidAudience = audience,//订阅人
|
||||
ValidateLifetime = true,//是否验证失效时间
|
||||
ClockSkew = TimeSpan.FromSeconds(60),
|
||||
RequireExpirationTime = true,
|
||||
};
|
||||
|
||||
// core自带官方JWT认证,开启Bearer认证
|
||||
services.AddAuthentication(o =>
|
||||
{
|
||||
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
o.DefaultChallengeScheme = nameof(ApiResponseForAdminHandler);
|
||||
o.DefaultForbidScheme = nameof(ApiResponseForAdminHandler);
|
||||
})
|
||||
// 添加JwtBearer服务
|
||||
.AddJwtBearer(o =>
|
||||
{
|
||||
o.TokenValidationParameters = tokenValidationParameters;
|
||||
o.Events = new JwtBearerEvents
|
||||
{
|
||||
OnChallenge = context =>
|
||||
{
|
||||
context.Response.Headers.Add("Token-Error", context.ErrorDescription);
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
OnAuthenticationFailed = context =>
|
||||
{
|
||||
var token = context.Request.Headers["Authorization"].ObjectToString().Replace("Bearer ", "");
|
||||
var jwtToken = (new JwtSecurityTokenHandler()).ReadJwtToken(token);
|
||||
|
||||
if (jwtToken.Issuer != issuer)
|
||||
{
|
||||
context.Response.Headers.Add("Token-Error-Iss", "issuer is wrong!");
|
||||
}
|
||||
|
||||
if (jwtToken.Audiences.FirstOrDefault() != audience)
|
||||
{
|
||||
context.Response.Headers.Add("Token-Error-Aud", "Audience is wrong!");
|
||||
}
|
||||
|
||||
// 如果过期,则把<是否过期>添加到,返回头信息中
|
||||
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
|
||||
{
|
||||
context.Response.Headers.Add("Token-Expired", "true");
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
})
|
||||
.AddScheme<AuthenticationSchemeOptions, ApiResponseForAdminHandler>(nameof(ApiResponseForAdminHandler), o => { });
|
||||
|
||||
|
||||
// 注入权限处理器
|
||||
services.AddScoped<IAuthorizationHandler, PermissionForAdminHandler>();
|
||||
services.AddSingleton(permissionRequirement);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 前端客户jwt初始化设置
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public static void AddAuthorizationSetupForClient(this IServiceCollection services)
|
||||
{
|
||||
if (services == null) throw new ArgumentNullException(nameof(services));
|
||||
|
||||
#region 参数
|
||||
//读取配置文件
|
||||
var symmetricKeyAsBase64 = AppSettingsConstVars.JwtConfigSecretKey;
|
||||
var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
|
||||
var signingKey = new SymmetricSecurityKey(keyByteArray);
|
||||
var issuer = AppSettingsConstVars.JwtConfigIssuer;
|
||||
var audience = AppSettingsConstVars.JwtConfigAudience;
|
||||
|
||||
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
// 如果要数据库动态绑定,这里先留个空,后边处理器里动态赋值
|
||||
var permission = new List<PermissionItem>();
|
||||
|
||||
// 角色与接口的权限要求参数
|
||||
var permissionRequirement = new PermissionRequirement(
|
||||
"/api/denied",// 拒绝授权的跳转地址(目前无用)
|
||||
permission,
|
||||
ClaimTypes.Role,//基于角色的授权
|
||||
issuer,//发行人
|
||||
audience,//听众
|
||||
signingCredentials,//签名凭据
|
||||
expiration: TimeSpan.FromSeconds(60 * 60 * 24)//接口的过期时间
|
||||
);
|
||||
#endregion
|
||||
|
||||
// 复杂的策略授权
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy(Permissions.Name, policy => policy.Requirements.Add(permissionRequirement));
|
||||
});
|
||||
|
||||
|
||||
// 令牌验证参数
|
||||
var tokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true, //是否验证SecurityKey
|
||||
IssuerSigningKey = signingKey, //拿到SecurityKey
|
||||
ValidateIssuer = true, //是否验证Issuer
|
||||
ValidIssuer = issuer,//发行人
|
||||
ValidateAudience = true, //是否验证Audience
|
||||
ValidAudience = audience,//订阅人
|
||||
ValidateLifetime = true, //是否验证失效时间
|
||||
ClockSkew = TimeSpan.FromSeconds(60),
|
||||
RequireExpirationTime = true,
|
||||
};
|
||||
|
||||
// core自带官方JWT认证,开启Bearer认证
|
||||
services.AddAuthentication(o =>
|
||||
{
|
||||
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
o.DefaultChallengeScheme = nameof(ApiResponseForClientHandler);
|
||||
o.DefaultForbidScheme = nameof(ApiResponseForClientHandler);
|
||||
})
|
||||
// 添加JwtBearer服务
|
||||
.AddJwtBearer(o =>
|
||||
{
|
||||
o.TokenValidationParameters = tokenValidationParameters;
|
||||
o.Events = new JwtBearerEvents
|
||||
{
|
||||
OnChallenge = context =>
|
||||
{
|
||||
context.Response.Headers.Add("Token-Error", context.ErrorDescription);
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
OnAuthenticationFailed = context =>
|
||||
{
|
||||
var token = context.Request.Headers["Authorization"].ObjectToString().Replace("Bearer ", "");
|
||||
var jwtToken = (new JwtSecurityTokenHandler()).ReadJwtToken(token);
|
||||
|
||||
if (jwtToken.Issuer != issuer)
|
||||
{
|
||||
context.Response.Headers.Add("Token-Error-Iss", "issuer is wrong!");
|
||||
}
|
||||
|
||||
if (jwtToken.Audiences.FirstOrDefault() != audience)
|
||||
{
|
||||
context.Response.Headers.Add("Token-Error-Aud", "Audience is wrong!");
|
||||
}
|
||||
|
||||
// 如果过期,则把<是否过期>添加到,返回头信息中
|
||||
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
|
||||
{
|
||||
context.Response.Headers.Add("Token-Expired", "true");
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
})
|
||||
.AddScheme<AuthenticationSchemeOptions, ApiResponseForClientHandler>(nameof(ApiResponseForClientHandler), o => { });
|
||||
|
||||
|
||||
// 注入权限处理器
|
||||
services.AddScoped<IAuthorizationHandler, PermissionForClientHandler>();
|
||||
services.AddSingleton(permissionRequirement);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
20
CoreCms.Net.Auth/CoreCms.Net.Auth.csproj
Normal file
20
CoreCms.Net.Auth/CoreCms.Net.Auth.csproj
Normal file
@@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.13.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CoreCms.Net.Configuration\CoreCms.Net.Configuration.csproj" />
|
||||
<ProjectReference Include="..\CoreCms.Net.IRepository\CoreCms.Net.IRepository.csproj" />
|
||||
<ProjectReference Include="..\CoreCms.Net.IServices\CoreCms.Net.IServices.csproj" />
|
||||
<ProjectReference Include="..\CoreCms.Net.Utility\CoreCms.Net.Utility.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
33
CoreCms.Net.Auth/HttpContextSetup.cs
Normal file
33
CoreCms.Net.Auth/HttpContextSetup.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using CoreCms.Net.Auth.HttpContextUser;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace CoreCms.Net.Auth
|
||||
{
|
||||
/// <summary>
|
||||
/// 上下文启动
|
||||
/// </summary>
|
||||
public static class HttpContextSetup
|
||||
{
|
||||
public static void AddHttpContextSetup(this IServiceCollection services)
|
||||
{
|
||||
if (services == null) throw new ArgumentNullException(nameof(services));
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
services.AddScoped<IHttpContextUser, AspNetUser>();
|
||||
}
|
||||
}
|
||||
}
|
||||
75
CoreCms.Net.Auth/HttpContextUser/AspNetUser.cs
Normal file
75
CoreCms.Net.Auth/HttpContextUser/AspNetUser.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using CoreCms.Net.Utility.Extensions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace CoreCms.Net.Auth.HttpContextUser
|
||||
{
|
||||
public class AspNetUser : IHttpContextUser
|
||||
{
|
||||
private readonly IHttpContextAccessor _accessor;
|
||||
|
||||
public AspNetUser(IHttpContextAccessor accessor)
|
||||
{
|
||||
_accessor = accessor;
|
||||
}
|
||||
|
||||
public string Name => _accessor.HttpContext.User.Identity.Name;
|
||||
public int ID => GetClaimValueByType("jti").FirstOrDefault().ObjectToInt();
|
||||
|
||||
public bool IsAuthenticated()
|
||||
{
|
||||
return _accessor.HttpContext.User.Identity.IsAuthenticated;
|
||||
}
|
||||
|
||||
public string GetToken()
|
||||
{
|
||||
return _accessor.HttpContext.Request.Headers["Authorization"].ObjectToString().Replace("Bearer ", "");
|
||||
}
|
||||
|
||||
public List<string> GetUserInfoFromToken(string ClaimType)
|
||||
{
|
||||
|
||||
var jwtHandler = new JwtSecurityTokenHandler();
|
||||
if (!string.IsNullOrEmpty(GetToken()))
|
||||
{
|
||||
JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(GetToken());
|
||||
|
||||
return (from item in jwtToken.Claims
|
||||
where item.Type == ClaimType
|
||||
select item.Value).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new List<string>() { };
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Claim> GetClaimsIdentity()
|
||||
{
|
||||
return _accessor.HttpContext.User.Claims;
|
||||
}
|
||||
|
||||
public List<string> GetClaimValueByType(string ClaimType)
|
||||
{
|
||||
|
||||
return (from item in GetClaimsIdentity()
|
||||
where item.Type == ClaimType
|
||||
select item.Value).ToList();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
29
CoreCms.Net.Auth/HttpContextUser/IHttpContextUser.cs
Normal file
29
CoreCms.Net.Auth/HttpContextUser/IHttpContextUser.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
|
||||
namespace CoreCms.Net.Auth.HttpContextUser
|
||||
{
|
||||
public interface IHttpContextUser
|
||||
{
|
||||
string Name { get; }
|
||||
int ID { get; }
|
||||
bool IsAuthenticated();
|
||||
IEnumerable<Claim> GetClaimsIdentity();
|
||||
List<string> GetClaimValueByType(string ClaimType);
|
||||
|
||||
string GetToken();
|
||||
List<string> GetUserInfoFromToken(string ClaimType);
|
||||
}
|
||||
}
|
||||
125
CoreCms.Net.Auth/OverWrite/JwtHelper.cs
Normal file
125
CoreCms.Net.Auth/OverWrite/JwtHelper.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using CoreCms.Net.Configuration;
|
||||
using CoreCms.Net.Utility.Extensions;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace CoreCms.Net.Auth.OverWrite
|
||||
{
|
||||
public class JwtHelper
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 颁发JWT字符串
|
||||
/// </summary>
|
||||
/// <param name="tokenModel"></param>
|
||||
/// <returns></returns>
|
||||
public static string IssueJwt(TokenModelJwt tokenModel)
|
||||
{
|
||||
string iss = AppSettingsConstVars.JwtConfigIssuer;
|
||||
string aud = AppSettingsConstVars.JwtConfigAudience;
|
||||
string secret = AppSettingsConstVars.JwtConfigSecretKey;
|
||||
|
||||
//var claims = new Claim[] //old
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
/*
|
||||
* 特别重要:
|
||||
1、这里将用户的部分信息,比如 uid 存到了Claim 中,如果你想知道如何在其他地方将这个 uid从 Token 中取出来,请看下边的SerializeJwt() 方法,或者在整个解决方案,搜索这个方法,看哪里使用了!
|
||||
2、你也可以研究下 HttpContext.User.Claims ,具体的你可以看看 Policys/PermissionHandler.cs 类中是如何使用的。
|
||||
*/
|
||||
|
||||
new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ToString()),
|
||||
new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
|
||||
new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
|
||||
//这个就是过期时间,目前是过期1000秒,可自定义,注意JWT有自己的缓冲过期时间
|
||||
new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds()}"),
|
||||
new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(1000).ToString()),
|
||||
new Claim(JwtRegisteredClaimNames.Iss,iss),
|
||||
new Claim(JwtRegisteredClaimNames.Aud,aud)
|
||||
|
||||
//new Claim(ClaimTypes.Role,tokenModel.Role),//为了解决一个用户多个角色(比如:Admin,System),用下边的方法
|
||||
};
|
||||
|
||||
// 可以将一个用户的多个角色全部赋予;
|
||||
// 作者:DX 提供技术支持;
|
||||
claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
|
||||
|
||||
//秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
|
||||
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
var jwt = new JwtSecurityToken(
|
||||
issuer: iss,
|
||||
claims: claims,
|
||||
signingCredentials: creds);
|
||||
|
||||
var jwtHandler = new JwtSecurityTokenHandler();
|
||||
var encodedJwt = jwtHandler.WriteToken(jwt);
|
||||
|
||||
return encodedJwt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析
|
||||
/// </summary>
|
||||
/// <param name="jwtStr"></param>
|
||||
/// <returns></returns>
|
||||
public static TokenModelJwt SerializeJwt(string jwtStr)
|
||||
{
|
||||
var jwtHandler = new JwtSecurityTokenHandler();
|
||||
JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
|
||||
object role;
|
||||
try
|
||||
{
|
||||
jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
var tm = new TokenModelJwt
|
||||
{
|
||||
Uid = (jwtToken.Id).ObjectToInt(),
|
||||
Role = role != null ? role.ObjectToString() : ""
|
||||
};
|
||||
return tm;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 令牌
|
||||
/// </summary>
|
||||
public class TokenModelJwt
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public long Uid { get; set; }
|
||||
/// <summary>
|
||||
/// 角色
|
||||
/// </summary>
|
||||
public string Role { get; set; }
|
||||
/// <summary>
|
||||
/// 职能
|
||||
/// </summary>
|
||||
public string Work { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
96
CoreCms.Net.Auth/OverWrite/JwtTokenAuth.cs
Normal file
96
CoreCms.Net.Auth/OverWrite/JwtTokenAuth.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace CoreCms.Net.Auth.OverWrite
|
||||
{
|
||||
/// <summary>
|
||||
/// 中间件
|
||||
/// 原做为自定义授权中间件
|
||||
/// 先做检查 header token的使用
|
||||
/// </summary>
|
||||
public class JwtTokenAuth
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private readonly RequestDelegate _next;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="next"></param>
|
||||
public JwtTokenAuth(RequestDelegate next)
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
|
||||
private void PreProceed(HttpContext next)
|
||||
{
|
||||
//Console.WriteLine($"{DateTime.Now} middleware invoke preproceed");
|
||||
//...
|
||||
}
|
||||
private void PostProceed(HttpContext next)
|
||||
{
|
||||
//Console.WriteLine($"{DateTime.Now} middleware invoke postproceed");
|
||||
//....
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <returns></returns>
|
||||
public Task Invoke(HttpContext httpContext)
|
||||
{
|
||||
PreProceed(httpContext);
|
||||
|
||||
//检测是否包含'Authorization'请求头
|
||||
if (!httpContext.Request.Headers.ContainsKey("Authorization"))
|
||||
{
|
||||
PostProceed(httpContext);
|
||||
|
||||
return _next(httpContext);
|
||||
}
|
||||
//var tokenHeader = httpContext.Request.Headers["Authorization"].ToString();
|
||||
var tokenHeader = httpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
|
||||
|
||||
try
|
||||
{
|
||||
if (tokenHeader.Length >= 128)
|
||||
{
|
||||
//Console.WriteLine($"{DateTime.Now} token :{tokenHeader}");
|
||||
TokenModelJwt tm = JwtHelper.SerializeJwt(tokenHeader);
|
||||
//授权
|
||||
//var claimList = new List<Claim>();
|
||||
//var claim = new Claim(ClaimTypes.Role, tm.Role);
|
||||
//claimList.Add(claim);
|
||||
//var identity = new ClaimsIdentity(claimList);
|
||||
//var principal = new ClaimsPrincipal(identity);
|
||||
//httpContext.User = principal;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"{DateTime.Now} middleware wrong:{e.Message}");
|
||||
}
|
||||
|
||||
PostProceed(httpContext);
|
||||
return _next(httpContext);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
56
CoreCms.Net.Auth/Policys/ApiResponse.cs
Normal file
56
CoreCms.Net.Auth/Policys/ApiResponse.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CoreCms.Net.Auth.Policys
|
||||
{
|
||||
public class ApiResponse
|
||||
{
|
||||
public int Status { get; set; } = 404;
|
||||
public object Value { get; set; } = "No Found";
|
||||
|
||||
public ApiResponse(StatusCode apiCode, object msg = null)
|
||||
{
|
||||
switch (apiCode)
|
||||
{
|
||||
case StatusCode.CODE401:
|
||||
{
|
||||
Status = 401;
|
||||
Value = "很抱歉,您无权访问该接口,请确保已经登录!";
|
||||
}
|
||||
break;
|
||||
case StatusCode.CODE403:
|
||||
{
|
||||
Status = 403;
|
||||
Value = "很抱歉,您的访问权限等级不够,联系管理员!";
|
||||
}
|
||||
break;
|
||||
case StatusCode.CODE500:
|
||||
{
|
||||
Status = 500;
|
||||
Value = msg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum StatusCode
|
||||
{
|
||||
CODE401,
|
||||
CODE403,
|
||||
CODE404,
|
||||
CODE500
|
||||
}
|
||||
}
|
||||
62
CoreCms.Net.Auth/Policys/ApiResponseForAdminHandler.cs
Normal file
62
CoreCms.Net.Auth/Policys/ApiResponseForAdminHandler.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.Model.ViewModels.UI;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CoreCms.Net.Auth.Policys
|
||||
{
|
||||
public class ApiResponseForAdminHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||
{
|
||||
public ApiResponseForAdminHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||
{
|
||||
Response.ContentType = "application/json";
|
||||
//Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
//await Response.WriteAsync(JsonConvert.SerializeObject(new ApiResponse(StatusCode.CODE401)));
|
||||
|
||||
var jm = new AdminUiCallBack();
|
||||
jm.code = 401;
|
||||
jm.data = 401;
|
||||
jm.msg = "很抱歉,您无权访问该接口,请确保已经登录!";
|
||||
await Response.WriteAsync(JsonConvert.SerializeObject(jm));
|
||||
}
|
||||
|
||||
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||
{
|
||||
Response.ContentType = "application/json";
|
||||
//Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
//await Response.WriteAsync(JsonConvert.SerializeObject(new ApiResponse(StatusCode.CODE403)));
|
||||
|
||||
var jm = new AdminUiCallBack();
|
||||
jm.code = 403;
|
||||
jm.msg = "很抱歉,您的访问权限等级不够,联系管理员!!";
|
||||
await Response.WriteAsync(JsonConvert.SerializeObject(jm));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
65
CoreCms.Net.Auth/Policys/ApiResponseForClientHandler.cs
Normal file
65
CoreCms.Net.Auth/Policys/ApiResponseForClientHandler.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.Model.ViewModels.UI;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CoreCms.Net.Auth.Policys
|
||||
{
|
||||
public class ApiResponseForClientHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||
{
|
||||
public ApiResponseForClientHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||
{
|
||||
Response.ContentType = "application/json";
|
||||
//Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
//await Response.WriteAsync(JsonConvert.SerializeObject(new ApiResponse(StatusCode.CODE401)));
|
||||
|
||||
var jm = new WebApiCallBack();
|
||||
jm.status = false;
|
||||
jm.code = 14007;
|
||||
jm.data = 14007;
|
||||
jm.msg = "很抱歉,授权失效,请重新登录!";
|
||||
await Response.WriteAsync(JsonConvert.SerializeObject(jm));
|
||||
}
|
||||
|
||||
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||
{
|
||||
Response.ContentType = "application/json";
|
||||
//Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
//await Response.WriteAsync(JsonConvert.SerializeObject(new ApiResponse(StatusCode.CODE403)));
|
||||
|
||||
var jm = new WebApiCallBack();
|
||||
jm.status = false;
|
||||
jm.code = 14007;
|
||||
jm.data = 14007;
|
||||
jm.msg = "很抱歉,授权失效,请重新登录!";
|
||||
await Response.WriteAsync(JsonConvert.SerializeObject(jm));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
56
CoreCms.Net.Auth/Policys/JwtToken.cs
Normal file
56
CoreCms.Net.Auth/Policys/JwtToken.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
|
||||
namespace CoreCms.Net.Auth.Policys
|
||||
{
|
||||
/// <summary>
|
||||
/// JWTToken生成类
|
||||
/// </summary>
|
||||
public class JwtToken
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取基于JWT的Token
|
||||
/// </summary>
|
||||
/// <param name="claims">需要在登陆的时候配置</param>
|
||||
/// <param name="permissionRequirement">在startup中定义的参数</param>
|
||||
/// <returns></returns>
|
||||
public static dynamic BuildJwtToken(Claim[] claims, PermissionRequirement permissionRequirement)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
// 实例化JwtSecurityToken
|
||||
var jwt = new JwtSecurityToken(
|
||||
issuer: permissionRequirement.Issuer,
|
||||
audience: permissionRequirement.Audience,
|
||||
claims: claims,
|
||||
notBefore: now,
|
||||
expires: now.Add(permissionRequirement.Expiration),
|
||||
signingCredentials: permissionRequirement.SigningCredentials
|
||||
);
|
||||
// 生成 Token
|
||||
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
|
||||
|
||||
//打包返回前台
|
||||
var responseJson = new
|
||||
{
|
||||
success = true,
|
||||
token = encodedJwt,
|
||||
expires_in = permissionRequirement.Expiration.TotalSeconds,
|
||||
token_type = "Bearer"
|
||||
};
|
||||
return responseJson;
|
||||
}
|
||||
}
|
||||
}
|
||||
210
CoreCms.Net.Auth/Policys/PermissionForAdminHandler.cs
Normal file
210
CoreCms.Net.Auth/Policys/PermissionForAdminHandler.cs
Normal file
@@ -0,0 +1,210 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.Configuration;
|
||||
using CoreCms.Net.IServices;
|
||||
using CoreCms.Net.Utility.Extensions;
|
||||
using CoreCms.Net.Utility.Helper;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace CoreCms.Net.Auth.Policys
|
||||
{
|
||||
/// <summary>
|
||||
/// 权限授权处理器
|
||||
/// </summary>
|
||||
public class PermissionForAdminHandler : AuthorizationHandler<PermissionRequirement>
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证方案提供对象
|
||||
/// </summary>
|
||||
public IAuthenticationSchemeProvider Schemes { get; set; }
|
||||
private readonly ISysRoleMenuServices _sysRoleMenuServices;
|
||||
private readonly IHttpContextAccessor _accessor;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数注入
|
||||
/// </summary>
|
||||
/// <param name="schemes"></param>
|
||||
/// <param name="navigationRepository"></param>
|
||||
/// <param name="accessor"></param>
|
||||
public PermissionForAdminHandler(IAuthenticationSchemeProvider schemes
|
||||
, ISysRoleMenuServices sysRoleMenuServices
|
||||
, IHttpContextAccessor accessor)
|
||||
{
|
||||
_accessor = accessor;
|
||||
Schemes = schemes;
|
||||
_sysRoleMenuServices = sysRoleMenuServices;
|
||||
}
|
||||
|
||||
// 重写异步处理程序
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
|
||||
{
|
||||
|
||||
var httpContext = _accessor.HttpContext;
|
||||
|
||||
if (!requirement.Permissions.Any())
|
||||
{
|
||||
var data = await _sysRoleMenuServices.RoleModuleMaps();
|
||||
var list = new List<PermissionItem>();
|
||||
|
||||
if (Permissions.IsUseIds4)
|
||||
{
|
||||
list = (from item in data
|
||||
orderby item.id
|
||||
select new PermissionItem
|
||||
{
|
||||
Url = item.menu?.component,
|
||||
RouteUrl = item.menu?.path,
|
||||
Authority = item.menu?.authority,
|
||||
Role = item.role?.id.ObjectToString(),
|
||||
}).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
list = (from item in data
|
||||
orderby item.id
|
||||
select new PermissionItem
|
||||
{
|
||||
Url = item.menu?.component,
|
||||
RouteUrl = item.menu?.path,
|
||||
Authority = item.menu?.authority,
|
||||
Role = item.role?.roleCode,
|
||||
}).ToList();
|
||||
}
|
||||
requirement.Permissions = list;
|
||||
}
|
||||
|
||||
//请求Url
|
||||
if (httpContext != null)
|
||||
{
|
||||
//
|
||||
var questUrl = httpContext.Request.Path.Value.ToLower();
|
||||
//判断请求是否停止
|
||||
var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
|
||||
foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
|
||||
{
|
||||
if (await handlers.GetHandlerAsync(httpContext, scheme.Name) is IAuthenticationRequestHandler handler && 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;
|
||||
|
||||
// 获取当前用户的角色信息
|
||||
var currentUserRoles = new List<string>();
|
||||
|
||||
// ids4和jwt切换
|
||||
// ids4
|
||||
if (Permissions.IsUseIds4)
|
||||
{
|
||||
currentUserRoles = (from item in httpContext.User.Claims
|
||||
where item.Type == "role"
|
||||
select item.Value).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
// jwt
|
||||
currentUserRoles = (from item in httpContext.User.Claims
|
||||
where item.Type == requirement.ClaimType
|
||||
select item.Value).ToList();
|
||||
}
|
||||
|
||||
var isMatchRole = false;
|
||||
var permisssionRoles = requirement.Permissions.Where(w => currentUserRoles.Contains(w.Role));
|
||||
foreach (var item in permisssionRoles)
|
||||
{
|
||||
try
|
||||
{
|
||||
//权限中是否存在请求的url
|
||||
if (Regex.Match(questUrl, item.Url.ObjectToString().ToLower()).Value == questUrl)
|
||||
{
|
||||
isMatchRole = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
//验证权限
|
||||
if (currentUserRoles.Count <= 0 || !isMatchRole)
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
var isExp = false;
|
||||
|
||||
// ids4和jwt切换
|
||||
// ids4
|
||||
if (Permissions.IsUseIds4)
|
||||
{
|
||||
isExp = (httpContext.User.Claims.SingleOrDefault(s => s.Type == "exp")?.Value) != null && DateHelper.StampToDateTime(httpContext.User.Claims.SingleOrDefault(s => s.Type == "exp")?.Value) >= DateTime.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
// jwt
|
||||
isExp = (httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) != null && DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) >= DateTime.Now;
|
||||
}
|
||||
if (isExp)
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
//判断没有登录时,是否访问登录的url,并且是Post请求,并且是form表单提交类型,否则为失败
|
||||
//if (!questUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) && (!httpContext.Request.Method.Equals("POST") || !httpContext.Request.HasJsonContentType()))
|
||||
//{
|
||||
// context.Fail();
|
||||
// return;
|
||||
//}
|
||||
}
|
||||
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
}
|
||||
182
CoreCms.Net.Auth/Policys/PermissionForClientHandler.cs
Normal file
182
CoreCms.Net.Auth/Policys/PermissionForClientHandler.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.Utility.Extensions;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace CoreCms.Net.Auth.Policys
|
||||
{
|
||||
/// <summary>
|
||||
/// 权限授权处理器
|
||||
/// </summary>
|
||||
public class PermissionForClientHandler : AuthorizationHandler<PermissionRequirement>
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证方案提供对象
|
||||
/// </summary>
|
||||
public IAuthenticationSchemeProvider Schemes { get; set; }
|
||||
private readonly IHttpContextAccessor _accessor;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数注入
|
||||
/// </summary>
|
||||
/// <param name="schemes"></param>
|
||||
/// <param name="navigationRepository"></param>
|
||||
/// <param name="accessor"></param>
|
||||
public PermissionForClientHandler(IAuthenticationSchemeProvider schemes, IHttpContextAccessor accessor)
|
||||
{
|
||||
_accessor = accessor;
|
||||
Schemes = schemes;
|
||||
}
|
||||
|
||||
// 重写异步处理程序
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
|
||||
{
|
||||
|
||||
var httpContext = _accessor.HttpContext;
|
||||
|
||||
if (!requirement.Permissions.Any())
|
||||
{
|
||||
//var data = await _navigationRepository.QueryAsync();
|
||||
//var list = (from item in data
|
||||
// where item.isLock == false
|
||||
// orderby item.id
|
||||
// select new PermissionItem
|
||||
// {
|
||||
// Url = item.linkUrl,
|
||||
// Role = item.identificationCode,
|
||||
// }).ToList();
|
||||
//requirement.Permissions = list;
|
||||
}
|
||||
|
||||
//请求Url
|
||||
if (httpContext != null)
|
||||
{
|
||||
var questUrl = httpContext.Request.Path.Value.ToLower();
|
||||
//判断请求是否停止
|
||||
var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
|
||||
foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
|
||||
{
|
||||
if (await handlers.GetHandlerAsync(httpContext, scheme.Name) is IAuthenticationRequestHandler handler && 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)
|
||||
{
|
||||
// 将最新的角色和接口列表更新
|
||||
|
||||
// 这里暂时把代码移动到了Login获取token的api里,这样就不用每次都请求数据库,造成压力.
|
||||
// 但是这样有个问题,就是如果修改了某一个角色的菜单权限,不会立刻更新,
|
||||
// 需要让用户退出重新登录,如果你想实时更新,请把下边的注释打开即可.
|
||||
|
||||
//var data = await _roleModulePermissionServices.RoleModuleMaps();
|
||||
//var list = (from item in data
|
||||
// where item.IsDeleted == false
|
||||
// orderby item.Id
|
||||
// select new PermissionItem
|
||||
// {
|
||||
// Url = item.Module?.LinkUrl,
|
||||
// Role = item.Role?.Name,
|
||||
// }).ToList();
|
||||
//requirement.Permissions = list;
|
||||
|
||||
httpContext.User = result.Principal;
|
||||
|
||||
//权限中是否存在请求的url
|
||||
//if (requirement.Permissions.GroupBy(g => g.Url).Where(w => w.Key?.ToLower() == questUrl).Count() > 0)
|
||||
//if (isMatchUrl)
|
||||
if (true)
|
||||
{
|
||||
// 获取当前用户的角色信息
|
||||
var currentUserRoles = (from item in httpContext.User.Claims
|
||||
where item.Type == requirement.ClaimType
|
||||
select item.Value).ToList();
|
||||
|
||||
var isMatchRole = false;
|
||||
var permisssionRoles = requirement.Permissions.Where(w => currentUserRoles.Contains(w.Role));
|
||||
foreach (var item in permisssionRoles)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Regex.Match(questUrl, item.Url?.ObjectToString().ToLower())?.Value == questUrl)
|
||||
{
|
||||
isMatchRole = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
//验证权限
|
||||
//if (currentUserRoles.Count <= 0 || requirement.Permissions.Where(w => currentUserRoles.Contains(w.Role) && w.Url.ToLower() == questUrl).Count() <= 0)
|
||||
if (currentUserRoles.Count <= 0 || !isMatchRole)
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//判断过期时间(这里仅仅是最坏验证原则,你可以不要这个if else的判断,因为我们使用的官方验证,Token过期后上边的result?.Principal 就为 null 了,进不到这里了,因此这里其实可以不用验证过期时间,只是做最后严谨判断)
|
||||
if ((httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) != null && DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value) >= DateTime.Now)
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Fail();
|
||||
return;
|
||||
}
|
||||
//判断没有登录时,是否访问登录的url,并且是Post请求,并且是form表单提交类型,否则为失败
|
||||
//if (!questUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) && (!httpContext.Request.Method.Equals("POST") || !httpContext.Request.HasJsonContentType()))
|
||||
//{
|
||||
// context.Fail();
|
||||
// return;
|
||||
//}
|
||||
}
|
||||
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
CoreCms.Net.Auth/Policys/PermissionItem.cs
Normal file
40
CoreCms.Net.Auth/Policys/PermissionItem.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CoreCms.Net.Auth.Policys
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户或角色或其他凭据实体
|
||||
/// </summary>
|
||||
public class PermissionItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户或角色或其他凭据名称
|
||||
/// </summary>
|
||||
public virtual string Role { get; set; }
|
||||
/// <summary>
|
||||
/// 请求Url
|
||||
/// </summary>
|
||||
public virtual string Url { get; set; }
|
||||
/// <summary>
|
||||
/// 权限标识
|
||||
/// </summary>
|
||||
public virtual string Authority { get; set; }
|
||||
/// <summary>
|
||||
/// 路由标识Url
|
||||
/// </summary>
|
||||
public virtual string RouteUrl { get; set; }
|
||||
}
|
||||
}
|
||||
83
CoreCms.Net.Auth/Policys/PermissionRequirement.cs
Normal file
83
CoreCms.Net.Auth/Policys/PermissionRequirement.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace CoreCms.Net.Auth.Policys
|
||||
{
|
||||
/// <summary>
|
||||
/// 必要参数类
|
||||
/// 继承 IAuthorizationRequirement,用于设计自定义权限处理器PermissionHandler
|
||||
/// 因为AuthorizationHandler 中的泛型参数 TRequirement 必须继承 IAuthorizationRequirement
|
||||
/// </summary>
|
||||
public class PermissionRequirement : IAuthorizationRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户权限集合,一个订单包含了很多详情,
|
||||
/// 同理,一个网站的认证发行中,也有很多权限详情(这里是Role和URL的关系)
|
||||
/// </summary>
|
||||
public List<PermissionItem> Permissions { get; set; }
|
||||
/// <summary>
|
||||
/// 无权限action
|
||||
/// </summary>
|
||||
public string DeniedAction { get; set; }
|
||||
|
||||
/// <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; }
|
||||
/// <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>
|
||||
/// <param name="expiration">过期时间</param>
|
||||
public PermissionRequirement(string deniedAction, List<PermissionItem> permissions, string claimType, string issuer, string audience, SigningCredentials signingCredentials, TimeSpan expiration)
|
||||
{
|
||||
ClaimType = claimType;
|
||||
DeniedAction = deniedAction;
|
||||
Permissions = permissions;
|
||||
Issuer = issuer;
|
||||
Audience = audience;
|
||||
Expiration = expiration;
|
||||
SigningCredentials = signingCredentials;
|
||||
}
|
||||
}
|
||||
}
|
||||
131
CoreCms.Net.Auth/TokenHelper.cs
Normal file
131
CoreCms.Net.Auth/TokenHelper.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
/***********************************************************************
|
||||
* Project: CoreCms
|
||||
* ProjectName: 核心内容管理系统
|
||||
* Web: https://www.corecms.net
|
||||
* Author: 大灰灰
|
||||
* Email: jianweie@163.com
|
||||
* CreateTime: 2021/1/31 21:45:10
|
||||
* Description: 暂无
|
||||
***********************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CoreCms.Net.Configuration;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace CoreCms.Net.Auth
|
||||
{
|
||||
public class TokenHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Use the below code to generate symmetric Secret Key
|
||||
/// var hmac = new HMACSHA256();
|
||||
/// var key = Convert.ToBase64String(hmac.Key);
|
||||
/// </summary>
|
||||
private const string Secret = "db3OIsj+BXE9NZDy0t8W3TcNekrF+2d/1sFnWG4HnV8TZY30iTOdtVWJG8abWvB1GlOgJuQZdcF2Luqm/hccMw==";
|
||||
public static string GenerateToken(string username, int expireMinutes = 120)
|
||||
{ // 此方法用来生成 Token
|
||||
var symmetricKey = Convert.FromBase64String(Secret); // 生成二进制字节数组
|
||||
var tokenHandler = new JwtSecurityTokenHandler(); // 创建一个JwtSecurityTokenHandler类用来生成Token
|
||||
var now = DateTime.UtcNow; // 获取当前时间
|
||||
var tokenDescriptor = new SecurityTokenDescriptor // 创建一个 Token 的原始对象
|
||||
{
|
||||
Subject = new ClaimsIdentity(new[] // Token的身份证,类似一个人可以有身份证,户口本
|
||||
{
|
||||
new Claim(ClaimTypes.Name, username) // 可以创建多个
|
||||
}),
|
||||
|
||||
Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)), // Token 有效期
|
||||
|
||||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey), SecurityAlgorithms.HmacSha256)
|
||||
// 生成一个Token证书,第一个参数是根据预先的二进制字节数组生成一个安全秘钥,说白了就是密码,第二个参数是编码方式
|
||||
};
|
||||
var stoken = tokenHandler.CreateToken(tokenDescriptor); // 生成一个编码后的token对象实例
|
||||
var token = tokenHandler.WriteToken(stoken); // 生成token字符串,给前端使用
|
||||
return token;
|
||||
}
|
||||
public static ClaimsPrincipal GetPrincipal(string token)
|
||||
{ // 此方法用解码字符串token,并返回秘钥的信息对象
|
||||
try
|
||||
{
|
||||
var tokenHandler = new JwtSecurityTokenHandler(); // 创建一个JwtSecurityTokenHandler类,用来后续操作
|
||||
var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken; // 将字符串token解码成token对象
|
||||
if (jwtToken == null)
|
||||
return null;
|
||||
var symmetricKey = Convert.FromBase64String(Secret); // 生成编码对应的字节数组
|
||||
var validationParameters = new TokenValidationParameters() // 生成验证token的参数
|
||||
{
|
||||
RequireExpirationTime = true, // token是否包含有效期
|
||||
ValidateIssuer = false, // 验证秘钥发行人,如果要验证在这里指定发行人字符串即可
|
||||
ValidateAudience = false, // 验证秘钥的接受人,如果要验证在这里提供接收人字符串即可
|
||||
IssuerSigningKey = new SymmetricSecurityKey(symmetricKey) // 生成token时的安全秘钥
|
||||
};
|
||||
SecurityToken securityToken; // 接受解码后的token对象
|
||||
var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
|
||||
return principal; // 返回秘钥的主体对象,包含秘钥的所有相关信息
|
||||
}
|
||||
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 此方法用解码字符串token,并返回秘钥的信息对象
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public static int GetUserIdBySecurityToken(string token)
|
||||
{
|
||||
//读取配置文件
|
||||
var symmetricKeyAsBase64 = AppSettingsConstVars.JwtConfigSecretKey;
|
||||
var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
|
||||
var signingKey = new SymmetricSecurityKey(keyByteArray);
|
||||
var issuer = AppSettingsConstVars.JwtConfigIssuer;
|
||||
var audience = AppSettingsConstVars.JwtConfigAudience;
|
||||
|
||||
try
|
||||
{
|
||||
var tokenHandler = new JwtSecurityTokenHandler(); // 创建一个JwtSecurityTokenHandler类,用来后续操作
|
||||
var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken; // 将字符串token解码成token对象
|
||||
if (jwtToken == null)
|
||||
return 0;
|
||||
var validationParameters = new TokenValidationParameters() // 生成验证token的参数
|
||||
{
|
||||
ValidateIssuerSigningKey = true, //是否验证SecurityKey
|
||||
IssuerSigningKey = signingKey, //拿到SecurityKey
|
||||
ValidateIssuer = true, //是否验证Issuer
|
||||
ValidIssuer = issuer,//发行人 //Issuer,这两项和前面签发jwt的设置一致
|
||||
ValidateAudience = true, //是否验证Audience
|
||||
ValidAudience = audience,//订阅人
|
||||
ValidateLifetime = true,//是否验证失效时间
|
||||
ClockSkew = TimeSpan.FromSeconds(60),
|
||||
RequireExpirationTime = true,
|
||||
};
|
||||
SecurityToken securityToken; // 接受解码后的token对象
|
||||
var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
|
||||
|
||||
if (securityToken == null || string.IsNullOrEmpty(securityToken.Id))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return Convert.ToInt32(securityToken.Id); // 返回秘钥的主体对象,包含秘钥的所有相关信息
|
||||
}
|
||||
|
||||
catch
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user