找回密码
 立即注册
首页 业界区 业界 asp.net core 一种基于token 和 Permission 的权限管理F ...

asp.net core 一种基于token 和 Permission 的权限管理Filter 过滤器

计海龄 昨天 19:51
asp.net core webapi 下面,想做一个过滤权限的Filter,配合token,对api做一个较为细粒度的权限控制,
该filter (PermissionFilter) 的作用是用户LoginUser.Permissions 列表中有 Key指定的权限才可以访问,没有则返回403 错误码。
 
1. 先上封装后的使用效果
  1.         [Permission(Key = "/User/AddUser")]
  2.         [HttpPost]
  3.         public Result AddUser([FromBody] SaUser user)
  4.         {
  5.             //Do sth.
  6.             throw new NotImplementedException();
  7.         }<br>
复制代码
  1.     [Authorize]
  2.         [HttpPost]
  3.         public Result<UserInfoDto> GetUserInfo()
  4.         {
  5.              //Do sth.
  6.         }   
复制代码
  1.  
复制代码
说明:要求登录即可,不要求特定权限的,可以使用【Authroize】 attribute 标记,
  要求 特定权限 如   "/User/AddUser" 的 ,使用 【Permission】特性标记,使用Key指定需要的权限。 没有登录的返回401, 没有权限的返回403.
 
2. 实现。主要类及接口说明:
    LoginUser : 登录用户,包含用户基础信息,权限等。可以继承此类封装更多信息。
  1. namespace WebUtils
  2. {
  3.     public class LoginUser
  4.     {
  5.         public string EnterpriseId { get; set; }
  6.         public string UserName { get; set;}
  7.         public string Token { get; set; }
  8.         public DateTime LoginTime { get; set;}
  9.         /// <summary>
  10.         /// 可用权限
  11.         /// </summary>
  12.         public HashSet<string> Permissions { get; set;}
  13.     }
  14. }
复制代码
 
    ITokenHelper : 管理用户登录后的token,并根据token 获取登录用户信息。TUser 是LoginUser 的子类。 
  1. namespace WebUtils
  2. {
  3.     public interface  ITokenHelper<TUser>  where TUser :LoginUser
  4.     {
  5.         public void AddToken(string token, TUser user);
  6.         public void RemoveToken(string token);
  7.         public TUser GetLoginUser (string token);
  8.     }
  9. }
复制代码
 
    TokenHelper 是 ITokenHelper 的默认实现,LoginUser 和Token 存内存中,进程重启会丢失。实际应用可以封装自己的实现,把信息持久化到数据库或者Redis 中。
1.gif
2.gif
  1. namespace WebUtils
  2. {
  3.     public class TokenHelper : ITokenHelper<LoginUser>
  4.     {
  5.         
  6.         private Dictionary<string, LoginUser> UserDic = new Dictionary<string, LoginUser>();
  7.         
  8.         public void AddToken(string token, LoginUser au)
  9.         {
  10.             UserDic.Add(token, au);
  11.         }
  12.          
  13.         public LoginUser GetLoginUser(string token)
  14.         {
  15.             if (UserDic.ContainsKey(token))
  16.             {
  17.                 return UserDic[token];
  18.             }
  19.             return null;
  20.         }
  21.         public void RemoveToken(string token)
  22.         {
  23.             if (UserDic.ContainsKey(token))
  24.             {
  25.                 UserDic.Remove(token);
  26.             }
  27.         }
  28.     }
  29. }
复制代码
View Code 
    PermissionAuthenticationHandler:检查请求是否携带token,并检查TokenHelper 中是否包含此token.
3.gif
4.gif
  1. using Microsoft.AspNetCore.Authentication;
  2. using Microsoft.AspNetCore.Http;
  3. using Microsoft.Extensions.Logging;
  4. using Microsoft.Extensions.Options;
  5. using Microsoft.Extensions.Primitives;
  6. using System;
  7. using System.Net;
  8. using System.Security.Claims;
  9. using System.Text.Encodings.Web;
  10. using System.Threading.Tasks;
  11. using WebUtils;
  12. namespace WebUtils
  13. {
  14.     public class PermissionAuthenticationHandler : AuthenticationHandler
  15.     {
  16.         private ITokenHelper<LoginUser> _tokenHelper;
  17.         public PermissionAuthenticationHandler(ITokenHelper<LoginUser> tokenHelper, IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
  18.             : base(options, logger, encoder, clock)
  19.         {
  20.             this._tokenHelper = tokenHelper;
  21.         }
  22.         public static string CustomerSchemeName = "Permission";
  23.         protected override Task HandleAuthenticateAsync()
  24.         {
  25.             AuthenticateResult result;
  26.             Context.Request.Headers.TryGetValue("Authorization", out StringValues values);
  27.             string token = values.ToString();
  28.             if (!string.IsNullOrWhiteSpace(token))
  29.             {
  30.                 var loginInfo = _tokenHelper.GetLoginUser(token);
  31.                 if (loginInfo == null)
  32.                     result = AuthenticateResult.Fail("未登陆");
  33.                 else
  34.                 {
  35.                     var claimsIdentity = new ClaimsIdentity(new Claim[]
  36.                         {
  37.                                 new Claim(ClaimTypes.Name, loginInfo.UserName),
  38.                                 new Claim(ClaimHelper.EnterpriseId,loginInfo.EnterpriseId),
  39.                                 new Claim(ClaimHelper.Token, loginInfo.Token)
  40.                         }, CustomerSchemeName);
  41.                     var principal = new ClaimsPrincipal(claimsIdentity);
  42.                     AuthenticationTicket ticket = new AuthenticationTicket(principal, Scheme.Name);
  43.                     result = AuthenticateResult.Success(ticket);
  44.                 }
  45.             }
  46.             else
  47.             {
  48.                 result = AuthenticateResult.Fail("未登陆");
  49.             }
  50.             return Task.FromResult(result);
  51.         }
  52.     }
  53. }
复制代码
View Code 
    PermissionAttribute: 继承自 Attribute,IFilterFactory ,返回真正的IAuthorizationFilter实例。
    DonotUsePermissionFilterAttribute 继承自 Attribute, IAuthorizationFilter 检查是否拥有指定的权限。
5.gif
6.gif
  1. using Microsoft.AspNetCore.Mvc;
  2. using Microsoft.AspNetCore.Mvc.Filters;
  3. using Microsoft.Extensions.DependencyInjection;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace WebUtils
  10. {
  11.     [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
  12.     public class PermissionAttribute : Attribute,IFilterFactory
  13.     {
  14.         public string Key { get; set; }
  15.         public bool IsReusable => false;
  16.         public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
  17.         {
  18.             var instance= serviceProvider.GetService<DonotUsePermissionFilterAttribute>();
  19.             instance.Key = this.Key;
  20.             return instance;
  21.         }
  22.     }
  23.     /// <summary>
  24.     /// 防止用户直接调用,起名DonotUse,
  25.     /// </summary>
  26.     public class DonotUsePermissionFilterAttribute : Attribute, IAuthorizationFilter
  27.     {
  28.         private ITokenHelper<LoginUser> _tokenHelper;
  29.         public DonotUsePermissionFilterAttribute(ITokenHelper<LoginUser> tokenHelper)
  30.         {
  31.             this._tokenHelper = tokenHelper;
  32.         }
  33.         public string Key { get; set; }
  34.         public void OnAuthorization(AuthorizationFilterContext context)
  35.         {
  36.             var token = context.HttpContext.User?.GetValue(ClaimHelper.Token);
  37.             if (token == null)
  38.             {
  39.                 context.Result = new ObjectResult("用户未登录") { StatusCode = 401 };
  40.                 return;
  41.             }
  42.             var user = _tokenHelper.GetLoginUser(token);
  43.             if (user == null)
  44.             {
  45.                 context.Result = new ObjectResult("用户token 已失效") { StatusCode = 401 };
  46.                 return;
  47.             }
  48.             if (!user.Permissions.Contains(Key))
  49.             {
  50.                 context.Result = new ObjectResult("鉴权失败,请联系管理员授权!") { StatusCode = 403 };
  51.                 return;
  52.             }
  53.         }
  54.     }
  55. }
复制代码
View Code 
    
    PermissionMiddleWare 把相关实例和PermissionAuthenticationHandler添加到Service 中。
7.gif
8.gif
  1. using Microsoft.Extensions.DependencyInjection;
  2. namespace WebUtils
  3. {
  4.     public static class PermissionMiddleWare
  5.     {
  6.         /// <summary>
  7.         /// 基于token和permission 的权限认证中间件
  8.         /// </summary>
  9.         /// <param name="services"></param>
  10.         /// <param name="TokenHelperType"></param>
  11.         /// <returns></returns>
  12.         public static IServiceCollection AddPermission(this IServiceCollection services,Type TokenHelperType)
  13.         {
  14.             services.AddSingleton(typeof(ITokenHelper<LoginUser>), TokenHelperType);
  15.             services.AddTransient(typeof(PermissionAttribute));
  16.             services.AddTransient(typeof(DonotUsePermissionFilterAttribute));
  17.             services.AddAuthentication(o =>
  18.             {
  19.                 o.DefaultAuthenticateScheme = PermissionAuthenticationHandler.CustomerSchemeName;
  20.                 o.DefaultChallengeScheme = PermissionAuthenticationHandler.CustomerSchemeName;
  21.                 o.AddScheme<PermissionAuthenticationHandler>(PermissionAuthenticationHandler.CustomerSchemeName, PermissionAuthenticationHandler.CustomerSchemeName);
  22.             });
  23.             return services;
  24.         }
  25.     }
  26. }
复制代码
View Code 3. 在program.cs 中调用
  在原来添加AddAuthorization 的地方换成下面这句
  1.   builder.Services.AddPermission(typeof(TokenHelper));
复制代码
  别忘了后面use
  1.             app.UseAuthentication();
  2.             app.UseAuthorization();
复制代码
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册