博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
asp.net core利用DI实现自定义用户系统,脱离ControllerBase.User
阅读量:5125 次
发布时间:2019-06-13

本文共 6049 字,大约阅读时间需要 20 分钟。

前言

很多时候其实我们并不需要asp.net core自带的那么复杂的用户系统,基于角色,各种概念,还得用EF Core,而且在web应用中都是把信息存储到cookie中进行通讯(我不喜欢放cookie中,因为有次我在mac系统中的safari浏览器运行web应用时,碰到跨域cookie设不上,非要使用个很特殊的方法,记得是iframe,挺麻烦的,所以我还是喜欢放自定义header中), 用了以后感觉被微软给绑架了。不过这完全是个人喜好,大家完全可以按自己喜欢的来,我这里提供了另外一条路,大家可以多一种选择。

我这边是利用asp.net core的依赖注入,定义了一套属于自己系统的用户认证与授权,大家可以参考我这个来定义自己的,也不局限于用户系统。

面向切面编程(AOP)

在我看来,Middleware与Filter都是asp.net core中的切面,我们可以把认证与授权放到这两块地方。我个人比较喜欢把认证放到Middleware,可以提早把那些不合法的攻击拦截返回。

依赖注入(DI)

依赖注入有3种生命周期

1. 在同一个请求发起到结束。(services.AddScoped)

2. 每次注入的时候都是新建。(services.AddTransient)

3. 单例,应用开始到应用结束。(services.AddSingleton)

我的自定义用户类采用的是services.AddScoped。

具体做法

1. 定义用户类

1     // 用户类,随便写的2     public class MyUser3     {4         public string Token { get; set; }5         public string UserName { get; set; }6     }

2. 注册用户类

Startup.cs中的ConfigureServices函数:

1         // This method gets called by the runtime. Use this method to add services to the container.2         public void ConfigureServices(IServiceCollection services)3         {4             ...5             // 注册自定义用户类6             services.AddScoped(typeof(MyUser));7             ...8         }

自定义用户类,是通过services.AddScoped方式进行注册的,因为我希望它在同一个请求中,Middleware, filter, controller引用到的是同一个对象。

3. 注入到Middleware

1     // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project 2     public class AuthenticationMiddleware 3     { 4         private readonly RequestDelegate _next; 5         private IOptions
_optionsAccessor; 6 7 public AuthenticationMiddleware(RequestDelegate next, IOptions
optionsAccessor) 8 { 9 _next = next;10 _optionsAccessor = optionsAccessor;11 }12 13 public async Task Invoke(HttpContext httpContext, MyUser user)14 {15 var token = httpContext.Request.Headers[_optionsAccessor.Value.AuthHeader].FirstOrDefault();16 if (!IsValidate(token))17 {18 httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;19 httpContext.Response.ContentType = "text/plain";20 await httpContext.Response.WriteAsync("UnAuthentication");21 }22 else23 {24 // 设置用户的token25 user.Token = token;26 await _next(httpContext);27 }28 }29 30 // 随便写的,大家可以加入些加密,解密的来判断合法性,大家自由发挥31 private bool IsValidate(string token)32 {33 return !string.IsNullOrEmpty(token);34 }35 }36 37 // Extension method used to add the middleware to the HTTP request pipeline.38 public static class AuthenticationMiddlewareExtensions39 {40 public static IApplicationBuilder UseAuthenticationMiddleware(this IApplicationBuilder builder)41 {42 return builder.UseMiddleware
();43 }44 }

我发现如果要把接口/类以Scoped方式注入到Middleware中,就需要把要注入的类/接口放到Invoke函数的参数中,而不是Middleware的构造函数中,我猜这也是为什么Middleware没有继承基类或者接口,在基类或者接口中定义好Invoke的原因,如果它在基类或者接口中定义好Invoke,势必这个Invoke的参数要固定死,就不好依赖注入了。

4. 配置某些路径才会使用该Middleware

1         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 2         public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 3         { 4             loggerFactory.AddConsole(Configuration.GetSection("Logging")); 5             loggerFactory.AddDebug(); 6             // Set up nlog 7             loggerFactory.AddNLog(); 8             app.AddNLogWeb(); 9 10             // 除了特殊路径外,都需要加上认证的Middleware11             app.MapWhen(context => !context.Request.Path.StartsWithSegments("/api/token")12                                  && !context.Request.Path.StartsWithSegments("/swagger"), x =>13             {14                 // 使用自定义的Middleware15                 x.UseAuthenticationMiddleware();16                 // 使用通用的Middleware17                 ConfigCommonMiddleware(x);18             });19             // 使用通用的Middleware20             ConfigCommonMiddleware(app);21 22             // Enable middleware to serve generated Swagger as a JSON endpoint.23             app.UseSwagger();24 25             // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.26             app.UseSwaggerUI(c =>27             {28                 c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");29             });30         }31 32         // 配置通用的Middleware33         private void ConfigCommonMiddleware(IApplicationBuilder app)34         {35             // cors36             app.UseCors("AllowAll");37 38             app.UseExceptionMiddleware();39             // app.UseLogRequestMiddleware();40             app.UseMvc();41         }

像获取token啊,查看api文档啊就不需要认证了。

5. 注入到Filter

1     public class NeedAuthAttribute : ActionFilterAttribute 2     { 3         private string _name = string.Empty; 4         private MyUser _user; 5  6         public NeedAuthAttribute(MyUser user, string name = "") 7         { 8             _name = name; 9             _user = user;10         }11 12         public override void OnActionExecuting(ActionExecutingContext context)13         {14             this._user.UserName = "aaa";15         }16     }

这里我创建的是个带字符串参数的类,因为考虑到这个Filter有可能会被复用,比如限制某个接口只能被某种用户访问, 这个字符串便可以存某种用户的标识。

Filter中还可以注入数据库访问的类,这样我们便可以到数据库中通过token来获取到相应的用户信息。

6. 使用Filter

1 [TypeFilter(typeof(NeedAuthAttribute), Arguments = new object[]{ "bbb" }, Order = 1)]2 public class ValuesController : Controller

这里使用了TypeFilter,以加载使用了依赖注入的Filter, 并可以设置参数,跟Filter的顺序。

默认Filter的顺序是 全局设置->Controller->Action, Order默认都为0,我们可以通过设置Order来改变这个顺序。

7. 注入到Controller

1     public class ValuesController : Controller 2     { 3         private MyUser _user; 4  5         public ValuesController(MyUser user) 6         { 7             _user = user; 8         } 9         ...10     }

注入到Controller的构造函数中,这样我们就可以在Controller的Action中使用我们自定义的用户,就能知道到底当前是哪个用户在调用这个Action。

 

转载于:https://www.cnblogs.com/nickppa/p/6903694.html

你可能感兴趣的文章
CodeMeter 软件加密技术
查看>>
git 版本库之间的依赖
查看>>
仓库服务端软件artifactory
查看>>
Vulkan(0)搭建环境-清空窗口
查看>>
Vulkan(1)用apispec生成Vulkan库
查看>>
python全栈开发中级班全程笔记(第三模块、第一章(1.面向对象基础))
查看>>
python全栈开发中级班全程笔记(第三模块、第一章(多态、封装、反射、内置方法、元类、作业))...
查看>>
python全栈开发中级班全程笔记(第三模块、第二章(网络编程))
查看>>
30分钟部署一个Kubernetes集群
查看>>
gitlab部署
查看>>
gitlab数据迁移
查看>>
samba安装配置
查看>>
redis数据备份还原
查看>>
centos7 dns(bind)安装配置
查看>>
Keepalived+LVS+nginx搭建nginx高可用集群
查看>>
CAA调试
查看>>
BZOJ3123[Sdoi2013]森林——主席树+LCA+启发式合并
查看>>
BZOJ3523[Poi2014]Bricks——贪心+堆
查看>>
Android 二维码 生成和识别(附Demo源码)
查看>>
查询sql server占用内存的情况
查看>>