asp.net core webapi 下面,想做一個過濾權限的Filter,配合token,對api做一個較為細粒度的權限控制,
該filter (PermissionFilter) 的作用是用戶LoginUser.Permissions 列表中有 Key指定的權限才可以訪問,沒有則返回403 錯誤碼。
?
1. 先上封裝后的使用效果
[Permission(Key = "/User/AddUser")] [HttpPost] public Result AddUser([FromBody] SaUser user) { //Do sth. throw new NotImplementedException(); }
[Authorize] [HttpPost] public Result<UserInfoDto> GetUserInfo() { //Do sth. }
?
說明:要求登錄即可,不要求特定權限的,可以使用【Authroize】 attribute 標記,
要求 特定權限 如? ?"/User/AddUser" 的 ,使用 【Permission】特性標記,使用Key指定需要的權限。 沒有登錄的返回401, 沒有權限的返回403.
?
2. 實現(xiàn)。主要類及接口說明:
LoginUser : 登錄用戶,包含用戶基礎信息,權限等??梢岳^承此類封裝更多信息。
namespace WebUtils { public class LoginUser { public string EnterpriseId { get; set; } public string UserName { get; set;} public string Token { get; set; } public DateTime LoginTime { get; set;} /// <summary> /// 可用權限 /// </summary> public HashSet<string> Permissions { get; set;} } }
?
ITokenHelper <TUser>: 管理用戶登錄后的token,并根據(jù)token 獲取登錄用戶信息。TUser 是LoginUser 的子類。?
namespace WebUtils { public interface ITokenHelper<TUser> where TUser :LoginUser { public void AddToken(string token, TUser user); public void RemoveToken(string token); public TUser GetLoginUser (string token); } }
?
TokenHelper 是 ITokenHelper<LoginUser> 的默認實現(xiàn),LoginUser 和Token 存內(nèi)存中,進程重啟會丟失。實際應用可以封裝自己的實現(xiàn),把信息持久化到數(shù)據(jù)庫或者Redis 中。


namespace WebUtils { public class TokenHelper : ITokenHelper<LoginUser> { private Dictionary<string, LoginUser> UserDic = new Dictionary<string, LoginUser>(); public void AddToken(string token, LoginUser au) { UserDic.Add(token, au); } public LoginUser GetLoginUser(string token) { if (UserDic.ContainsKey(token)) { return UserDic[token]; } return null; } public void RemoveToken(string token) { if (UserDic.ContainsKey(token)) { UserDic.Remove(token); } } } }
?
PermissionAuthenticationHandler:檢查請求是否攜帶token,并檢查TokenHelper 中是否包含此token.


using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; using System; using System.Net; using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; using WebUtils; namespace WebUtils { public class PermissionAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions> { private ITokenHelper<LoginUser> _tokenHelper; public PermissionAuthenticationHandler(ITokenHelper<LoginUser> tokenHelper, IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { this._tokenHelper = tokenHelper; } public static string CustomerSchemeName = "Permission"; protected override Task<AuthenticateResult> HandleAuthenticateAsync() { AuthenticateResult result; Context.Request.Headers.TryGetValue("Authorization", out StringValues values); string token = values.ToString(); if (!string.IsNullOrWhiteSpace(token)) { var loginInfo = _tokenHelper.GetLoginUser(token); if (loginInfo == null) result = AuthenticateResult.Fail("未登陸"); else { var claimsIdentity = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, loginInfo.UserName), new Claim(ClaimHelper.EnterpriseId,loginInfo.EnterpriseId), new Claim(ClaimHelper.Token, loginInfo.Token) }, CustomerSchemeName); var principal = new ClaimsPrincipal(claimsIdentity); AuthenticationTicket ticket = new AuthenticationTicket(principal, Scheme.Name); result = AuthenticateResult.Success(ticket); } } else { result = AuthenticateResult.Fail("未登陸"); } return Task.FromResult(result); } } }
?
PermissionAttribute: 繼承自 Attribute,IFilterFactory ,返回真正的IAuthorizationFilter實例。
DonotUsePermissionFilterAttribute 繼承自?Attribute, IAuthorizationFilter 檢查是否擁有指定的權限。


using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WebUtils { [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)] public class PermissionAttribute : Attribute,IFilterFactory { public string Key { get; set; } public bool IsReusable => false; public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) { var instance= serviceProvider.GetService<DonotUsePermissionFilterAttribute>(); instance.Key = this.Key; return instance; } } /// <summary> /// 防止用戶直接調(diào)用,起名DonotUse, /// </summary> public class DonotUsePermissionFilterAttribute : Attribute, IAuthorizationFilter { private ITokenHelper<LoginUser> _tokenHelper; public DonotUsePermissionFilterAttribute(ITokenHelper<LoginUser> tokenHelper) { this._tokenHelper = tokenHelper; } public string Key { get; set; } public void OnAuthorization(AuthorizationFilterContext context) { var token = context.HttpContext.User?.GetValue(ClaimHelper.Token); if (token == null) { context.Result = new ObjectResult("用戶未登錄") { StatusCode = 401 }; return; } var user = _tokenHelper.GetLoginUser(token); if (user == null) { context.Result = new ObjectResult("用戶token 已失效") { StatusCode = 401 }; return; } if (!user.Permissions.Contains(Key)) { context.Result = new ObjectResult("鑒權失敗,請聯(lián)系管理員授權!") { StatusCode = 403 }; return; } } } }
?
PermissionMiddleWare 把相關實例和PermissionAuthenticationHandler添加到Service 中。


using Microsoft.Extensions.DependencyInjection; namespace WebUtils { public static class PermissionMiddleWare { /// <summary> /// 基于token和permission 的權限認證中間件 /// </summary> /// <param name="services"></param> /// <param name="TokenHelperType"></param> /// <returns></returns> public static IServiceCollection AddPermission(this IServiceCollection services,Type TokenHelperType) { services.AddSingleton(typeof(ITokenHelper<LoginUser>), TokenHelperType); services.AddTransient(typeof(PermissionAttribute)); services.AddTransient(typeof(DonotUsePermissionFilterAttribute)); services.AddAuthentication(o => { o.DefaultAuthenticateScheme = PermissionAuthenticationHandler.CustomerSchemeName; o.DefaultChallengeScheme = PermissionAuthenticationHandler.CustomerSchemeName; o.AddScheme<PermissionAuthenticationHandler>(PermissionAuthenticationHandler.CustomerSchemeName, PermissionAuthenticationHandler.CustomerSchemeName); }); return services; } } }
?3. 在program.cs 中調(diào)用
在原來添加AddAuthorization 的地方換成下面這句
builder.Services.AddPermission(typeof(TokenHelper));
別忘了后面use文章來源:http://www.zghlxwxcb.cn/news/detail-451665.html
app.UseAuthentication();
app.UseAuthorization();
?文章來源地址http://www.zghlxwxcb.cn/news/detail-451665.html
到了這里,關于asp.net core 一種基于token 和 Permission 的權限管理中間件示例的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!