asp.net core 一种基于token 和 Permission 的权限管理Filter 过滤器
asp.net core webapi 下面,想做一个过滤权限的Filter,配合token,对api做一个较为细粒度的权限控制,该filter (PermissionFilter) 的作用是用户LoginUser.Permissions 列表中有 Key指定的权限才可以访问,没有则返回403 错误码。
1. 先上封装后的使用效果
public Result AddUser( SaUser user)
{
//Do sth.
throw new NotImplementedException();
}<br>
public Result<UserInfoDto> GetUserInfo()
{
//Do sth.
} 说明:要求登录即可,不要求特定权限的,可以使用【Authroize】 attribute 标记,
要求 特定权限 如 "/User/AddUser" 的 ,使用 【Permission】特性标记,使用Key指定需要的权限。 没有登录的返回401, 没有权限的返回403.
2. 实现。主要类及接口说明:
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 : 管理用户登录后的token,并根据token 获取登录用户信息。TUser 是LoginUser 的子类。
namespace WebUtils
{
public interfaceITokenHelper<TUser>where TUser :LoginUser
{
public void AddToken(string token, TUser user);
public void RemoveToken(string token);
public TUser GetLoginUser (string token);
}
}
TokenHelper 是 ITokenHelper 的默认实现,LoginUser 和Token 存内存中,进程重启会丢失。实际应用可以封装自己的实现,把信息持久化到数据库或者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;
}
return null;
}
public void RemoveToken(string token)
{
if (UserDic.ContainsKey(token))
{
UserDic.Remove(token);
}
}
}
}View Code
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
{
private ITokenHelper<LoginUser> _tokenHelper;
public PermissionAuthenticationHandler(ITokenHelper<LoginUser> tokenHelper, IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
this._tokenHelper = tokenHelper;
}
public static string CustomerSchemeName = "Permission";
protected override Task 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);
}
}
}View Code
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
{
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>
/// 防止用户直接调用,起名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("鉴权失败,请联系管理员授权!") { StatusCode = 403 };
return;
}
}
}
}View Code
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;
}
}
}View Code 3. 在program.cs 中调用
在原来添加AddAuthorization 的地方换成下面这句
builder.Services.AddPermission(typeof(TokenHelper)); 别忘了后面use
app.UseAuthentication();
app.UseAuthorization();
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]