媒介
许多时刻实在我们并不须要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<HeaderConfig> _optionsAccessor; 6 7 public AuthenticationMiddleware(RequestDelegate next, IOptions<HeaderConfig> 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<AuthenticationMiddleware>();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。
以上就是asp.net core运用DI完成自定义用户体系的细致内容,更多请关注ki4网别的相干文章!