手写DotNet Core 认证授权代码
在普通的MVC项目中 我们普遍的使用Cookie来作为认证授权方式,使用简单。登录成功后将用户信息写入Cookie;但当我们做WebApi的时候显然Cookie这种方式就有点不适用了。
在.NET Core 中 WebApi中目前比较流行的认证授权方式是Jwt (Json Web Token) 技术。Jwt 是一种无状态的分布式身份验证方式,Jwt 是将用户登录信息加密后存放到返回的Token中 ,相当于用户信息是存储在客户端。Jwt的加密方式有两种 :对称加密与非对称加密,非对称加密即 RSA 加密的方式。
自己手写认证授权代码和Jwt的思路是一样的;不同之处在于:
1、加密方式仅仅是采用的对称加密方式 简单高效。哈哈!(弊端就是没有非对称加密更安全);
2、用户登录信息主要保存在Redis中,即服务端。
自己写的好处:
1、扩展性强,可根据自己的需要进行各种扩展,比如在验证授权时可很方便的添加多设备登录挤下线功能等。
2、可随时调整用户的Token失效时间。
认证及授权流程
1、先请求登录接口,登录成功,为用户产生一个Token,
登录获取Token 图片中ticket字段。

2、 客户端拿到Token在其他请求中将Token信息添加到请求头中传递到服务端。

开发思路
1、添加一个过滤器。在Startup 中ConfigureServices方法里添加一个Filters 即我们自己授权代码类。
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddMvc(mvc =>
{
//添加自己的授权验证
mvc.Filters.Add(typeof(AuthorizeFilter));
});
}
具体详细代码,请看文章结尾github地址。
添加过滤器之后我们的每次请求都会优先执行过滤器的代码。在这里我们就可以判断用户是否已经登录,从而进行拦截没有授权的的请求。
/// <summary>
/// 安全认证过滤器
/// </summary>
public class AuthorizeFilter : IActionFilter, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
//允许匿名访问
if (context.HttpContext.User.Identity.IsAuthenticated ||
context.Filters.Any(item => item is IAllowAnonymousFilter))
return;
var httpContext = context.HttpContext;
var claimsIdentity = httpContext.User.Identity as ClaimsIdentity;
var request = context.HttpContext.Request;
var authorization = request.Headers["Authorization"].ToString();
if (authorization != null && authorization.Contains("BasicAuth"))
{
//获取请求头中传递的ticket
var current_ticket = authorization.Split(" ")[];
//校验ticket并获取用户信息
var userInfo = TicketEncryption.VerifyTicket(current_ticket, out string dec_client);
if (userInfo != null)
{
//同一个终端多次登录挤下线功能 返回403
if (userInfo.ticket != current_ticket && userInfo.client.ToString() == dec_client)
{
#region 多设备挤下线代码
var response = new HttpResponseMessage();
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
context.Result = new JsonResult("Forbidden:The current authorization has expired");
#endregion return;
}
else
{
return;
}
} }
// 401 未授权
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Result = new JsonResult("Forbidden:Tiket Invalid"); }
}
具体详细代码,请看文章结尾github地址。
2、登录并获取Token
由于添加了IAuthorizationFilter类型的过滤器,所以每个请求都会被拦截。所以登录接口我们需要允许匿名访问。

3、加解密Token
加密:登录成功后就要产生个Token了,产生也简单。将用户的唯一信息比如uid或者guid进行对称式加密。当然如果需要对登录设备做区分或者多设备登录挤下线功能时最好也将登录设备一起加密进去。
我们都知道 在加密中一般情况下只要加密的数据及加密key不变;那么加密后的内容也会一直保持不变。如果我们每次登录产生的Token一直没有任何变化只要这个Token被泄露了那将很危险的。竟然我们希望每次登录产生的Token都有变化。那就要改变加密数据或者加密key了。加密数据是用户唯一信息这个显然不可能产生变化。所以我们能改变的地方只能是加密key了;我们采用固定key+随机key的方式。
因为加密key在我们解密时也是需要一一对应的。所以我们得想办法将我们的随机key告诉我们解密的代码中。办法就是 我们将加密后的内容(一般情况进行base64编码)再加上随机key。(随机key一定是固定长度 不然后面无法解析拆分)
比如加密内容是guid=73e01eab-210d-4d19-a72a-d0d64e053ec0+client=ios 固定key=123654+随机key=FEZaaWbyimaWiJHah
即加密过程:
加密(73e01eab-210d-4d19-a72a-d0d64e053ec0&ios,123654FEZaaWbyimaWiJHah)=M0EzM0ZGRjk2QzgwRDY2RDJDMTdFOEJGRUE0NDI3NEE1RDlFNkU4NDQ0MERFNEIyMkQ5QjM4MjAxODcwj加随机key:FEZaaWbyimaWiJHah
所以我们返回给用户的Token实际上是包含了随机key的。当然这个随机key只有我们自己知道。因为随机key的长度以及位置只有我们自己知道。这种方式即使我们固定key被泄露了 只要别人不知道我们随机key处理方法也无济于事。
解密:知道加密过程后就好解密了。拿到用户提交的Token后首先按照随机key的固定位置进行截取。将加密内容和随机key拆开。然后将固定key和随机key组合一起解密加密的内容,取得用户guid和登录的客户端类型。
完整加解密代码
代码中的ticket代表本文中的Token。代码中使用的是DES加解密
public class TicketEncryption
{
//加密key 实际中请用配置文件配置
private static readonly string key = "yvDlky7GXGtlPCGr";
/// <summary>
/// 获取一个新的ticket
/// </summary>
/// <param name="guid">用户的guid</param>
/// <param name="client">客户端</param>
/// <returns></returns>
public static string GenerateTicket(string guid, string client)
{
//随机key
string randomKey = Randoms.GetRandomString();
var keys = key + randomKey;
var desStr = Encryption.DesEncrypt(guid + "&" + client, keys);
var base64Str = Encryption.Base64Encrypt(desStr) + randomKey;
return base64Str;
} /// <summary>
/// 校验ticket
/// </summary>
/// <param name="encryptStr"></param>
/// <returns></returns>
public static UserInfo VerifyTicket(string encryptStr,out string client)
{
try
{
RedisHelper redisHelper = new RedisHelper("127.0.0.1:6379");
//加密原型:guid&client; 如:08e80f78-95ad-427c-b506-a5f1504e29ac&ios
string randomKey = encryptStr.Substring(encryptStr.Length - );
var base64 = encryptStr.Substring(, encryptStr.Length - );
var deBase64 = Encryption.Base64Decrypt(base64);
var keys = key + randomKey;
string ticketInfo = Encryption.DesDecrypt(deBase64, keys);
var guid = ticketInfo.Split("&")[];
client = ticketInfo.Split("&")[];
string redisKey = "ticket_" + guid;
var obj = redisHelper.Get<UserInfo>(redisKey);
return obj;
}
catch (Exception ex)
{
throw ex;
}
}
}
完整demo代码请看github
https://github.com/cfan1236/NetCoreAuthorize
手写DotNet Core 认证授权代码的更多相关文章
- SpringSecurity(1)---认证+授权代码实现
认证+授权代码实现 Spring Security是 一种基于 Spring AOP 和 Servlet 过滤器的安全框架.它提供全面的安全性解决方案,同时在 Web 请求级和方法调用级处理身份确认和 ...
- 4.2tensorflow多层感知器MLP识别手写数字最易懂实例代码
自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取: https://www.cnblogs.com/bclshuai/p/11380657.html 1.1 多层感知器MLP(m ...
- 手写笔记变PDF-几行代码变命令行程序为图形化界面
前言 最近发现了一个非常不错的Python类库----Gooey, https://github.com/chriskiehl/Gooey 在它的帮助下我们可以非常方便的将一个命令行程序升级成一个图形 ...
- 手写数字0-9的识别代码(SVM支持向量机)
帮一个贴吧的朋友改的一段代码,源代码来自<机器学习实战> 原代码的功能是识别0和9两个数字 经过改动之后可以识别0~9,并且将分类器的产生和测试部分分开来写,免得每次测试数据都要重新生成分 ...
- .net core 认证与授权(三)
前言 在写三上是在一的基础上写的,所以有没有看过二是没得关系的,在一中介绍了认证与授权,但是没有去介绍拿到证书后怎样去验证授权. 概念性东西:在这套机制中,把这个权限认证呢,称作为policy.这个p ...
- 手写RPC框架指北另送贴心注释代码一套
Angular8正式发布了,Java13再过几个月也要发布了,技术迭代这么快,框架的复杂度越来越大,但是原理是基本不变的.所以沉下心看清代码本质很重要,这次给大家带来的是手写RPC框架. 完整代码以及 ...
- 常见的JS手写函数汇总(代码注释、持续更新)
最近在复习面试中常见的JS手写函数,顺便进行代码注释和总结,方便自己回顾也加深记,内容也会陆陆续续进行补充和改善. 一.手写深拷贝 <script> const obj1 = { name ...
- Spring security OAuth2.0认证授权学习第三天(认证流程)
本来之前打算把第三天写基于Session认证授权的,但是后来视屏看完后感觉意义不大,而且内容简单,就不单独写成文章了; 简单说一下吧,就是通过Servlet的SessionApi 通过实现拦截器的前置 ...
- springcloud-alibaba手写负载均衡的坑,采用restTemplate,不能添加@loadbalanced注解,否则采用了robbin
采用springcloud-alibaba整合rabbion使用DiscoveryClient调用restful时遇到的一个问题,报错如下: D:\javaDevlepTool\java1.8\jdk ...
随机推荐
- nginx安装配置+集群tomcat:Centos和windows环境
版本:nginx-1.8.0.tar.gz 官网:http://nginx.org/en/download.html 版本:apache-tomcat-6.0.44.tar.gz 官 ...
- 基于reflectasm打造自己的通用bean工具
业务场景: 在很多的业务系统中,erp,crm系统中,有许多的对象信息都是拆开来的,例如一个商品,那可能他的商品名称,商品等主要信息放在一个表(衍生出来一个对象),他的附属信息(商品图片,规格,价格等 ...
- 服务治理利器Hystrix-理论篇
引言 现在的大中型应用,很多都在朝着服务化.分布式的方向发展.这有多方面的考虑,比如说,方便治理.便于扩展.服务隔离等等.不过在带来如此多利好的同时,不可避免的也会带来麻烦,比如系统架构复杂.服务依赖 ...
- zfs文件系统简单使用
关于ubuntu下zfs的使用参考:https://github.com/zfsonlinux/zfs/wiki/Ubuntu%2016.04%20Root%20on%20ZFS 安装zfs: 启动z ...
- Python_单元测试
Stack.py class Stack: def __init__(self, size = 10): self._content = [] #使用列表存放栈的元素 self._size = siz ...
- 令状态寄存器访问指令(MRS,MSR)
ARM中有两条指令用于在状态寄存器和通用寄存器之间传送数据. 针对32位的ARM处理器,状态寄存器就是一个32位长的寄存器.每个位的含义如下图: 分成了4部分: 1,条件标志位 N(Negative) ...
- CentOS7 安装 MySQL
一.首先检查 MySQL 是否已安装 yum list installed | grep mysql 如果有的话 就全部卸载 yum -y remove +数据库名称 二.MySQL 依赖 libai ...
- linux下安装nginx与配置
linux系统为Centos 64位 第一步:从http://nginx.org/download/上下载相应的版本(或者wget http://nginx.org/download/nginx-1. ...
- Linux kernel的中断子系统之(九):tasklet
返回目录:<ARM-Linux中断系统>. 总结: 二介绍了tasklet存在的意义. 三介绍了通过tasklet_struct来抽想一个tasklet,每个CPU维护一个tasklet链 ...
- 静态代码扫描工具PMD定制xml的规则(一)操作篇
0.前言 PMD作为开源的静态代码扫描工具有很强的扩展能力,可使用java或xpath定制rule.第一篇从操作上讲解如何定制一个用于扫描xml是否规范的规则.首先我们知道xml格式的文件在java工 ...