ASP.NET Core - 基于IHttpContextAccessor实现系统级别身份标识
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了ASP.NET Core - 基于IHttpContextAccessor实现系统级别身份标识,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4525字,纯文字阅读大概需要7分钟。
内容图文
问题引入:
我们知道当请求通过认证模块时,会给当前的HttpContext赋予当前用户身份标识,我们在需要授权的控制器中打上[Authorize]授权标签,就可以在ControllerBase的User属性获取到基于声明的权限标识(ClaimsPrincipal)。这只是针对Controller层面,遗憾的是很多场景下我们是需要在Service层乃至数据层获直接使用用户信息,这种情况我们就使用不了User了。
在Asp.net 4.x时代,我们通常通过HttpContext.Current获取当前请求的上下文进而获取到当前的User属性,而Aspnet Core则是通过注入HttpContext的访问器对象IHttpContextAccessor来获取当前的HttpContext。
解决方案:
问题的解决在于我们如何获取当前的HttpContext上下文,首先我们需要注册IHttpContextAccessor的实例
public void ConfigureServices(IServiceCollection services) { services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); .... }
有了这个注册,我们封装一个方法从IHttpContextAccessor 的HttpContext中获取对应的ClaimsPrincipal,如下:
public class PrincipalAccessor : IPrincipalAccessor {
//没有通过认证的,User会为空 public ClaimsPrincipal Principal => _httpContextAccessor.HttpContext?.User; private readonly IHttpContextAccessor _httpContextAccessor; public PrincipalAccessor(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } } public interface IPrincipalAccessor { ClaimsPrincipal Principal { get; } }
我们一样把这个类也加入注册中
public void ConfigureServices(IServiceCollection services) { services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton<IPrincipalAccessor, PrincipalAccessor>(); .... }
有了这些东西,那我们需要的是如何从ClaimsPrincipal获取到对应的Claims了
public class ClaimsAccessor : IClaimsAccessor { protected IPrincipalAccessor PrincipalAccessor { get; } public ClaimsAccessor(IPrincipalAccessor principalAccessor) { PrincipalAccessor = principalAccessor; } /// <summary> /// 登录用户ID /// </summary> public int? ApiUserId { get { var userId = PrincipalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type == SystemClaimTypes.UserId)?.Value; if (userId != null) { int id = 0; int.TryParse(userId, out id); return id; } return null; } } /// <summary> /// 用户角色Id /// </summary> public string RoleIds { get { var roleIds = PrincipalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type == SystemClaimTypes.RoleIds)?.Value; if (string.IsNullOrWhiteSpace(roleIds)) { return string.Empty; } return roleIds; } } } public interface IClaimsAccessor { /// <summary> /// 登录用户ID /// </summary> int? ApiUserId { get; } /// <summary> /// 用户角色Id /// </summary> string RoleIds{ get; } }
同样我们把它注册进来
public void ConfigureServices(IServiceCollection services) { services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton<IPrincipalAccessor, PrincipalAccessor>(); services.AddSingleton<IClaimsAccessor, ClaimsAccessor>(); .... }
好的让我们看看该如何使用
public class TestService : ITestService { private readonly IClaimsAccessor _claims; private readonly IRepository<Product> _productRepository; public TestService(IClaimsAccessor claims, IRepository<Product> productRepository) { _claims = claims; _productRepository = productRepository; } public Result AddProduct(ProductDto dto) { _productRepository.Insert(new Product { Name = dto.Name, ... CreatorUserId = _claims.ApiUserId }); } }
至此我们的系统级别的标识已经完成,只需通过注入的方式即可。
改进
我们发现了如果每个服务都按照上面的写法的话,每次都需要手动进行构造注入会比较繁琐,可以创建基类进行继承
public abstract class ServiceBase { /// <summary> /// 身份信息 /// </summary> protected IClaimsAccessor Claims { get; set; } /// <summary> /// cotr /// </summary> protected ServiceBase () { Claims = ServiceProviderInstance.Instance.GetRequiredService<IClaimsAccessor>(); } }
上面用到了ServiceProviderInstance,这里主要是利用了
public class ServiceProviderInstance { public static IServiceProvider Instance { get; set; } }
ServiceProviderInstance的实例是在应用启动的时候把当前的IServiceProvider保存起来
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { ... ServiceProviderInstance.Instance = app.ApplicationServices; }
好的让我们看看改进后该如何使用
public class TestService : ServiceBase,ITestService { private readonly IRepository<Product> _productRepository; public TestService(IRepository<Product> productRepository) { _productRepository = productRepository; } public Result AddProduct(ProductDto dto) { _productRepository.Insert(new Product { Name = dto.Name, ... CreatorUserId = Claims.ApiUserId }); } }
这样每个子类都继承了基类的认证信息而不用写太多的重复代码。
让我知道如果你有更好的想法或建议!
内容总结
以上是互联网集市为您收集整理的ASP.NET Core - 基于IHttpContextAccessor实现系统级别身份标识全部内容,希望文章能够帮你解决ASP.NET Core - 基于IHttpContextAccessor实现系统级别身份标识所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。