前言

很多时候其实我们并不需要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 = )]
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 core利用DI实现自定义用户系统,脱离ControllerBase.User的更多相关文章

  1. asp.net core系列 47 Identity 自定义用户数据

    一.概述 接着上篇的WebAppIdentityDemo项目,将自定义用户数据添加到Identity DB,自定义扩展的用户数据类应继承IdentityUser类, 文件名为Areas / Ident ...

  2. asp.net core的DI框架思考以及服务实例的获取方式总结

    转载请注明出处: https://home.cnblogs.com/u/zhiyong-ITNote/ 整个asp.net core管道从WebHostBuilder到WebHost到后续请求的类中, ...

  3. Asp.Net Core中DI的知识总结

    在asp.net core中DI的概念是由这几部分组成的: IServiceCollection,保存IServiceDescriptor实例的列表 IServiceProvider,只有一个方法Ge ...

  4. 实战Asp.Net Core:DI生命周期

    title: 实战Asp.Net Core:DI生命周期 date: 2018-11-30 21:54:52 --- 1.前言 Asp.Net Core 默认支持 DI(依赖注入) 软件设计模式,那使 ...

  5. asp.net core参数保护之自定义要保护的参数类型

    asp.net core参数保护之自定义要保护的参数类型 Intro 为了实现 asp.net core 下的参数保护,扩展了asp.net core 中 DataProtection,可以自动化的保 ...

  6. ASP.NET Core的路由[2]:路由系统的核心对象——Router

    ASP.NET Core应用中的路由机制实现在RouterMiddleware中间件中,它的目的在于通过路由解析为请求找到一个匹配的处理器,同时将请求携带的数据以路由参数的形式解析出来供后续请求处理流 ...

  7. 基于Microsoft Azure、ASP.NET Core和Docker的博客系统

    欢迎阅读daxnet的新博客:一个基于Microsoft Azure.ASP.NET Core和Docker的博客系统   2008年11月,我在博客园开通了个人帐号,并在博客园发表了自己的第一篇博客 ...

  8. [ASP.NET Core 3框架揭秘] 服务承载系统[1]: 承载长时间运行的服务[上篇]

    借助.NET Core提供的承载(Hosting)系统,我们可以将任意一个或者多个长时间运行(Long-Running)的服务寄宿或者承载于托管进程中.ASP.NET Core应用仅仅是该承载系统的一 ...

  9. 【asp.net core 系列】15 自定义Identity

    0. 前言 在之前的文章中简单介绍了一下asp.net core中的Identity,这篇文章将继续针对Identity进行进一步的展开. 1. 给Identity添加额外的信息 在<[asp. ...

随机推荐

  1. SpringMVC文件上传下载

    不多说,代码: Spring-config.xml<!-- spring可以自动去扫描base-pack下面的包或者子包下面的java文件, 如果扫描到有Spring的相关注解的类,则把这些类注 ...

  2. android-studio-bundle-141.2178183首次执行Hello World的时候出现ADB not responding. If you'd like to retry, then please manually kill "adb.e的错误

    这是由于有其他程序在占用adb.exe要使用的端口5037,打开命令提示符cmd,输入指令netstat -aon|findstr 5037查看在使用此端口的程序,如 8036即为占用该端口号的PID ...

  3. MongDB系列(一):使用node.js连接数据库

    1.首先启动mongodb数据库服务器 2.创建app.js,代码如下: /** * Created by byzy on 2016/8/18. * node.js 连接 mongodb实例 */ / ...

  4. 五子棋AI大战OC实现

    Gobang 五子棋AI大战,该项目主要用到MVC框架,用算法搭建AI实现进攻或防守 一.项目介绍 1.地址: github地址:Gobang 2.效果图: 二.思路介绍 大概说下思路,具体看代码实现 ...

  5. STM32学习笔记(四)——串口控制LED(中断方式)

    目录: 一.时钟使能,包括GPIO的时钟和串口的时钟使能 二.设置引脚复用映射 三.GPIO的初始化配置,注意要设置为复用模式 四.串口参数初始化配置 五.中断分组和中断优先级配置 六.设置串口中断类 ...

  6. storage在IE8下的兼容性写法

    storage 本地缓存,这是HTML5的一个非常好用的地方,具体好用在哪,网上可以找到很多,但是我觉得总结的都不是很完整,我建议大家有空的话可以看下JavaScript权威指南这本书,里面对于这个方 ...

  7. C#网络程序设计(2)Socket基础编程

        本节介绍如何使用基础Socket实现TCP通信.     (1)Socket详细介绍: Socket的英文原义是"孔"或"插座".通常称作"套 ...

  8. Mvc Ajax提交多个checkbox,也说绑定和提交select

    Ajax Mvc的 checkbox 后端必须是List<T> ,T是ID类型,一般int 或guid 模型必须初始化List<T> 防止客户端没有提交任何值时空引用的问题,如 ...

  9. 有些arp请求报文中为什么会有目的mac地址(不使用广播地址)

    有些arp请求报文中为什么会有目的mac地址(不使用广播地址) 最近做实验,注意到局域网内大部分的arp包的以太网头部目的mac地址并不是广播地址,并且包内的目的mac地址字段并不是全0,而是目的ip ...

  10. input 显示/隐藏密码

    js代码: // 显示/隐藏密码 $('.open').on('click',function(){ if($("#psw").prop('type')=='password'){ ...