asp.net core利用DI实现自定义用户系统,脱离ControllerBase.User
2017-05-25 14:39
1061 查看
前言
很多时候其实我们并不需要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. 定义用户类
// 用户类,随便写的 public class MyUser { public string Token { get; set; } public string UserName { get; set; } }
2. 注册用户类
Startup.cs中的ConfigureServices函数:// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { ... // 注册自定义用户类 services.AddScoped(typeof(MyUser)); ... }
自定义用户类,是通过services.AddScoped方式进行注册的,因为我希望它在同一个请求中,Middleware, filter, controller引用到的是同一个对象。
3. 注入到Middleware
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project public class AuthenticationMiddleware { private readonly RequestDelegate _next; private IOptions<HeaderConfig> _optionsAccessor; public AuthenticationMiddleware(RequestDelegate next, IOptions<HeaderConfig> optionsAccessor) { _next = next; _optionsAccessor = optionsAccessor; } public async Task Invoke(HttpContext httpContext, MyUser user) { var token = httpContext.Request.Headers[_optionsAccessor.Value.AuthHeader].FirstOrDefault(); if (!IsValidate(token)) { httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; httpContext.Response.ContentType = "text/plain"; await httpContext.Response.WriteAsync("UnAuthentication"); } else { // 设置用户的token user.Token = token; await _next(httpContext); } } // 随便写的,大家可以加入些加密,解密的来判断合法性,大家自由发挥 private bool IsValidate(string token) { return !string.IsNullOrEmpty(token); } } // Extension method used to add the middleware to the HTTP request pipeline. public static class AuthenticationMiddlewareExtensions { public static IApplicationBuilder UseAuthenticationMiddleware(this IApplicationBuilder builder) { return builder.UseMiddleware<AuthenticationMiddleware>(); } }
我发现如果要把接口/类以Scoped方式注入到Middleware中,就需要把要注入的类/接口放到Invoke函数的参数中,而不是Middleware的构造函数中,我猜这也是为什么Middleware没有继承基类或者接口,在基类或者接口中定义好Invoke的原因,如果它在基类或者接口中定义好Invoke,势必这个Invoke的参数要固定死,就不好依赖注入了。
4. 配置某些路径才会使用该Middleware
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); // Set up nlog loggerFactory.AddNLog(); app.AddNLogWeb(); // 除了特殊路径外,都需要加上认证的Middleware app.MapWhen(context => !context.Request.Path.StartsWithSegments("/api/token") && !context.Request.Path.StartsWithSegments("/swagger"), x => { // 使用自定义的Middleware x.UseAuthenticationMiddleware(); // 使用通用的Middleware ConfigCommonMiddleware(x); }); // 使用通用的Middleware ConfigCommonMiddleware(app); // Enable middleware to serve generated Swagger as a JSON endpoint. app.UseSwagger(); // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint. app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); }); } // 配置通用的Middleware private void ConfigCommonMiddleware(IApplicationBuilder app) { // cors app.UseCors("AllowAll"); app.UseExceptionMiddleware(); // app.UseLogRequestMiddleware(); app.UseMvc(); }
像获取token啊,查看api文档啊就不需要认证了。
5. 注入到Filter
public class NeedAuthAttribute : ActionFilterAttribute { 3 private string _name = string.Empty; 4 private MyUser _user; public NeedAuthAttribute(MyUser user, string name = "") { _name = name; _user = user; } public override void OnActionExecuting(ActionExecutingContext context) { this._user.UserName = "aaa"; } }
这里我创建的是个带字符串参数的类,因为考虑到这个Filter有可能会被复用,比如限制某个接口只能被某种用户访问, 这个字符串便可以存某种用户的标识。
Filter中还可以注入数据库访问的类,这样我们便可以到数据库中通过token来获取到相应的用户信息。
6. 使用Filter
[TypeFilter(typeof(NeedAuthAttribute), Arguments = new object[]{ "bbb" }, Order = 1)] public class ValuesController : Controller
这里使用了TypeFilter,以加载使用了依赖注入的Filter, 并可以设置参数,跟Filter的顺序。
默认Filter的顺序是 全局设置->Controller->Action, Order默认都为0,我们可以通过设置Order来改变这个顺序。
7. 注入到Controller
public class ValuesController : Controller { private MyUser _user; public ValuesController(MyUser user) { _user = user; } ... }
注入到Controller的构造函数中,这样我们就可以在Controller的Action中使用我们自定义的用户,就能知道到底当前是哪个用户在调用这个Action。
相关文章推荐
- ASP.Net Mvc实现自定义User Identity用户身份识别系统(2)
- ASP.Net Mvc实现自定义User Identity用户身份识别系统(1)
- ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页
- ASP.NET系统用户权限设计与实现
- ASP.NET系统用户权限设计与实现(转)
- ASP.NET系统用户权限设计与实现
- ASP.NET系统用户权限设计与实现
- ASP.NET系统用户权限设计与实现
- ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页
- ASP.NET系统用户权限设计与实现
- ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页
- ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页
- ASP.NET系统用户权限设计与实现(转摘)
- ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页
- ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页
- ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页
- ASP.NET系统用户权限设计与实现(转摘)
- ASP.NET系统用户权限设计与实现(转摘)
- ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页[转]
- ASP.NET中利用DataGrid的自定义分页功能和存储过程结合实现高效分页