ASP.NET Core2利用Jwt技术在服务端实现对客户端的身份认证
背景
在微服务架构下,一般都会按不同的业务或功能将整个系统切分成不同的独立子系统,再通过REST API或RPC进行通讯并相互调用,形成各个子系统之间的串联结构。在这里,我们将采用REST API的通讯方式。
比如:
1、有一个“用户中心”独立子系统名为“Lezhima.UserHub”,是一个基于ASP.NET Core mvc 2.0的项目。
2、有一个处理用户订单的独立子系统名为“Lezhima.UserOrder”,是一个基于ASP.NET Core webp api 2.0的项目。
3、同时还有一个处理用户文件上传的独立子系统名为“Lezhima.UserUpload”,是一个基于ASP.NET Core webp api 2.0的项目。
业务关系如下:
用户成功登录后进入“Lezhima.UserHub”,在用户查看订单时通过前端Ajax调用“Lezhima.UserOrder”的web api接口,在用户上传图片是通过前端Ajax调用“Lezhima.UserUpload”的web api接口。
至此,我们了解了上面的业务关系后,心里一定产生出如下两个问题:
1、如何保障“Lezhima.UserOrder”与“Lezhima.UserUpload”两个独立系统内的web api接口安全,因为它们已经被暴露在了前端。
2、如何在“Lezhima.UserHub”站颁发Token。
那么,带着问题我们下面就结合ASP.NET Core 自带的Jwt技术来讨论具体的实现(也许聪明的你有更好的解决方法,请一定告知我,谢谢)。
Jwt 全名为:JSON Web Token,是一个很成熟的技术,园子里也有很多这方面的知识,我这里就不再重述了。
实现原理
“Lezhima.UserHub”站因为已经做了登录验证,我们暂且认为它是可信的,所以在前端Ajax请求“Lezhima.UserOrder”站的web api接口时先到自已后端去生成一个Token,并随之同本次跨站请求一块携带至“Lezhima.UserOrder”站,“Lezhima.UserOrder”站验证请求头中的Token是否合法,如合法则继续路由到具体方法中,否则结束请求。“Lezhima.UserUpload”站原理与“Lezhima.UserOrder”相同。
实现代码
Lezhima.UserHub颁发Token代码:
/// <summary> /// 颁发一个指定有效期的Token,并将当前登录的用户id传递进来 /// </summary> /// <param name="currentUserId"></param> /// <param name="expiresMinutes"></param> /// <returns></returns> public static async Task<string> GetAccessToken(string currentUserId,int expiresMinutes=2) { return await Task.Run(() => { //约定私钥,下面三个参数可放到配置文件中 var secret = "NGUzNmNlNzQtZThkZC00YjRh"; //发行者 var iss = "Andre"; //接受者 var aud = "Andre"; if (string.IsNullOrEmpty(secret) || string.IsNullOrEmpty(iss) || string.IsNullOrEmpty(aud)) return ""; if (string.IsNullOrEmpty(currentUserId)) currentUserId = Guid.NewGuid().ToString(); var now = DateTime.UtcNow; var claims = new Claim[] { new Claim(JwtRegisteredClaimNames.Sub, currentUserId), new Claim(JwtRegisteredClaimNames.Iat, now.ToUniversalTime().ToString(), ClaimValueTypes.Integer64) }; var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secret)); var jwt = new JwtSecurityToken( issuer: iss, audience: aud, claims: claims, notBefore: now, expires: now.Add(TimeSpan.FromMinutes(expiresMinutes)), signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256) ); return new JwtSecurityTokenHandler().WriteToken(jwt); //生成一个新的token }); }
Lezhima.UserHub前端Ajax跨站请求代码:
//封装一个Ajax请求公共方法 function GetWebDataByObject(url, requestMethon, paramter) { jQuery.support.cors = true; apiUrl = 'http://127.0.0.1:8012/'; var token = GetToken(); //调用本站内的Token颁发Web api接口 var result = []; $.ajax({ type: requestMethon, url: apiUrl + url, data: paramter, async: false, beforeSend: function (xhr) { //将Token携带到请求头中 xhr.setRequestHeader("Authorization", "Bearer " + token); }, success: function (data) { result = data; }, error: function (XMLHttpRequest, textStatus, errorThrown) { // 状态码 console.log(XMLHttpRequest.status); // 状态 console.log(XMLHttpRequest.readyState); // 错误信息 console.log(textStatus); } }); return result; }
“Lezhima.UserOrder”站开启Jwt的Token验证,在Startup.cs里添加如下代码:
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddCors(); //从配置文件中获取私钥、发行者、接受者三个参数 //三个参数的值必需与颁发Token站相同 var audienceConfig = Configuration.GetSection("Audience"); var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(audienceConfig["Secret"])); var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = signingKey, ValidateIssuer = true, ValidIssuer = audienceConfig["Iss"], ValidateAudience = true, ValidAudience = audienceConfig["Aud"], ValidateLifetime = true, ClockSkew = TimeSpan.Zero, RequireExpirationTime = true, }; //注入Jwt验证 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.RequireHttpsMetadata = false; options.TokenValidationParameters = tokenValidationParameters; }); services.AddMvc(); var builder = new ContainerBuilder(); builder.RegisterModule(new Evolution()); builder.Populate(services); var container = builder.Build(); return container.Resolve<IServiceProvider>(); }
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseCors(builder => builder.WithOrigins("*") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials() ); //开启验证 app.UseAuthentication(); app.UseMvc(); }
“Lezhima.UserOrder”站内的控制器里添加验证过滤器[Authorize],如下代码:
[Route("api/[Controller]")] //添加过滤器后,该控制器内所有Action都将进行Token验证 [Authorize] public class OrderController : Controller { }
至此,基于ASP.NET Core的Jwt跨站验证Token方案就全部完成了,是不是很简单呀^_^ ^_^ !!
总结
1、Token颁发者与验证者都必需使用相同的私钥,私钥、发行者、接受者等参数可以放在配置文件中动态配置!
2、在项目Startup类中的ConfigureServices方法内添加注册使用Jwt身份验证的功能。
3、在验证者项目的控制器上或方法上加上过滤器 [Authorize]即可开启身份验证。
声明
本文为作者原创,转载请备注出处与保留原文地址,谢谢。如文章能给您带来帮助,请点下推荐或关注,感谢您的支持!
ASP.NET Core2利用Jwt技术在服务端实现对客户端的身份认证的更多相关文章
- centos 6.5环境利用iscsi搭建SAN网络存储服务及服务端target和客户端initiator配置详解
一.简介 iSCSI(internet SCSI)技术由IBM公司研究开发,是一个供硬件设备使用的.可以在IP协议的上层运行的SCSI指令集,这种指令集合可以实现在IP网络上运行SCSI协议,使其能够 ...
- WebService技术,服务端发布到Tomcat(使用Servlet发布),客户端使用axis2实现(二)
还是在WebService技术,服务端and客户端JDK-wsimport工具(一)的基础上实现.新建一个包:com.aixs2client.目录结构如下: 一.服务端: 1.还是使用com.webs ...
- app开发中如何利用sessionId来实现服务端与客户端保持回话
app开发中如何利用sessionId来实现服务端与客户端保持回话 这个问题太过于常见,也过于简单,以至于大部分开发者根本没有关注过这个问题,我根据和我沟通的开发者中,总结出来常用的方法有以下几种: ...
- 利用多线程使socket服务端可以与多个客户端同时通讯
利用多线程使socket服务端可以与多个客户端同时通讯 server import socket 1. 符合TCP协议的手机 server = socket.socket(socket.AF_INET ...
- WebService技术,服务端and客户端JDK-wsimport工具(一)
使用webservice服务,需要了解几个名词:soap 简单对象协议.http+xml . WSDL 先看下代码结构: 服务端代码与客户端代码分别处于两不同的包中 一.服务端内容 服务端: @Web ...
- 在ASP.NET Core中使用Angular2,以及与Angular2的Token base身份认证
注:下载本文提到的完整代码示例请访问:How to authorization Angular 2 app with asp.net core web api 在ASP.NET Core中使用Angu ...
- “快的打车”创始人陈伟星的新项目招人啦,高薪急招Java服务端/Android/Ios 客户端研发工程师/ mysql DBA/ app市场推广专家,欢迎大家加入我们的团队! - V2EX
"快的打车"创始人陈伟星的新项目招人啦,高薪急招Java服务端/Android/Ios 客户端研发工程师/ mysql DBA/ app市场推广专家,欢迎大家加入我们的团队! - ...
- java网络编程TCP传输—流操作—服务端反馈与客户端接收
在读取完流后,服务端会向客户端返回一些数据,告诉客户端,已经写完了. 在这里和”流操作—拿到源后的写入动作“差不多,客户端同样以byte与Buffered两种缓冲读取作为例子,同时,.也是希望大家给补 ...
- [发布]SuperIO v2.2.5 集成OPC服务端和OPC客户端
SuperIO 下载:本站下载 百度网盘 1.修复串口号大于等于10的时候导致IO未知状态. 2.优化RunIODevice(io)函数内部处理流程,二次开发可以重载这个接口. 3.优化IO接收数据, ...
随机推荐
- 02_java之数据类型和基本运算
01变量概述 * A: 什么是变量? * a: 变量是一个内存中的小盒子(小容器),容器是什么?生活中也有很多容器,例如水杯是容器,用来装载水:你家里的大衣柜是容器,用来装载衣裤:饭盒是容器,用来装载 ...
- 实验楼HTML基础入门学习
HTML基本介绍 HTML,一种描述网页的语言 结构 html head title script body ... 文档 <html> <head> <title> ...
- leetcode914
public class Solution { public bool HasGroupsSizeX(int[] deck) { var len = deck.Length; ; i <= le ...
- leetcode451
public class Solution { public string FrequencySort(string s) { var dic = new Dictionary<char, in ...
- 一个简单的语义分析算法:单步算法——Python实现
以前 曾经有一个人教会我一件事 要学会相信一些看似不可能的事 当你真的相信的时候 或许 没有什么事情是不可能的 ——<秦时明月•与子同归> 在编译原理的众多书籍中,陈述了很多生成语法树 ...
- Mysql Windows 7 异常关闭, 2003 - Can't connect to Mysql server on 'localhost' (10061) "Unknown error")
如下: 按Win+R在窗口输入services.msc 启动mysql服务
- FFmpeg多媒体文件格式探测
FFmpeg版本:3.4 在FFmpeg中,每一种文件容器格式都对应一种AVInputFormat 结构,位于源码中libavformat文件夹中.当调用avformat_open_input的时候, ...
- 深入理解Javascript中构造函数和原型对象的区别(转存)
Object是构造函数,而Object.prototype是构造函数的原型对象.构造函数自身的属性和方法无法被共享,而原型对象的属性和方法可以被所有实例对象所共享. 首先,我们知道,构造函数是生成对象 ...
- python实战===python控制键盘鼠标:pynput
Python控制键盘鼠标:pynput 地址:https://pypi.python.org/pypi/pynput 这个库让你可以控制和监控输入设备. 对于每一种输入设备,它包含一个子包来控制和监控 ...
- Ajax 简单实例,其实就是js里面内容有些不同而已(转载)
这些时间,瞎子也看得见,AJAX正大踏步的朝我们走来.不管我们是拥护也好,反对也罢,还是视而不见,AJAX像一阵潮流,席转了我们所有的人. 关于AJAX的定义也好,大话也好,早有人在网上发表了汗牛充栋 ...