ASP.NET Web API 2系列(四):基于JWT的token身份认证方案
1.引言
通过前边的系列教程,我们可以掌握WebAPI的初步运用,但是此时的API接口任何人都可以访问,这显然不是我们想要的,这时就需要控制对它的访问,也就是WebAPI的权限验证。验证方式非常多,本文就重点介绍一种常用的验证方式:基于JWT的token身份认证方案。
2.前期回顾
3.认识JWT
JWT是 JSON Web Token 的缩写,是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
3.1 JWT工作流程
这里我们通过一张图了解它的工作流程。
从上图中我们可以看出它是基于Token的身份认证,具体流程:客户端携带用户名和密码请求访问 - 服务器校验用户凭据 - 应用提供一个token给客户端 - 客户端存储token,并且在随后的每一次请求中都带着它 -服务器校验token并返回数据。
3.2JWT结构
JSON Web Token由三部分组成,它们之间用圆点(.)连接。这三部分分别是:
- Header:头部,它有token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)两部分组成;
- Payload:荷载,它包含声明(要求)。声明是关于实体(通常是用户)和其他数据的声明;
- Signature:签名,目的是用来验证头部和载荷是否被非法篡改。
通过下图,我们可以直观的看到JWT的组成。
它本质上是一个独立的身份验证令牌,可以包含用户标识、用户角色和权限等信息,以及您可以存储任何其他信息(自包含)。任何人都可以轻松读取和解析,并使用密钥来验证真实性。
4.具体实现
上文介绍了JWT的原理,读者简单了解即可,这里我们通过具体代码来实现。
4.1安装JWT包
通过NuGget管理工具安装JWT包,如下图
4.2添加LoginRequest、AuthInfo和HttpResult三个实体类
在MyWebAPI.Entities中添加相应类
LoginRequest实体
public class LoginRequest
{
public string UserId { get; set; }
public string Password { get; set; }
}
AuthInfo实体类
public class AuthInfo
{
public string UserId { get; set; }
public DateTime Expires { get; set; }
}
HttpResul实体类
public class HttpResult
{
public bool Success { get; set; }
public dynamic Data { get; set; }
public string Message { get; set; }
}
4.3添加SystemController,并添加Login登录方法
具体代码如下:
[RoutePrefix("api/System")]
public class SystemController : ApiController
{
[HttpPost, Route("Login")]
public HttpResult Login([FromBody] LoginRequest loginRequest)
{
if (loginRequest == null) return new HttpResult() { Success = false, Message = "登录信息为空!" };
#region 通过数据库判断登录信息是否正确(这里简化判断)
if (loginRequest.UserId != "admin" || loginRequest.Password != "admin")
{
return new HttpResult() { Success = false, Message = "用户名和密码不正确!" };
}
#endregion
AuthInfo authInfo = new AuthInfo()
{
UserId = loginRequest.UserId,
Expires = DateTime.Now.AddDays(1)
};
const string secretKey = "matanzhang";//口令加密秘钥(应该写到配置文件中)
byte[] key = Encoding.UTF8.GetBytes(secretKey);
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();//加密方式
IJsonSerializer serializer = new JsonNetSerializer();//序列化Json
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();//base64加解密
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);//JWT编码
var token = encoder.Encode(authInfo, key);//生成令牌
return new HttpResult() { Success = true, Data = token,Message = "登录成功!"};
}
}
4.4添加API过滤器ApiAuthorizeAttribute
具体代码如下:
public class ApiAuthorizeAttribute: AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
try
{
var authHeader = from t in actionContext.Request.Headers where t.Key == "auth" select t.Value.FirstOrDefault();
var enumerable = authHeader as string[] ?? authHeader.ToArray();
string token = enumerable.FirstOrDefault();
if (string.IsNullOrEmpty(enumerable.FirstOrDefault())) return false;
const string secretKey = "matanzhang";//口令加密秘钥(应该写到配置文件中)
byte[] key = Encoding.UTF8.GetBytes(secretKey);
IJsonSerializer serializer = new JsonNetSerializer();
IDateTimeProvider provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
//解密
var authInfo = decoder.DecodeToObject<AuthInfo>(token, key, verify: true);
if (authInfo != null)
{
//判断口令过期时间
if (authInfo.Expires < DateTime.Now)
{
return false;
}
actionContext.RequestContext.RouteData.Values.Add("auth", authInfo);
return true;
}
}
catch (Exception e)
{
}
return false;
}
/// <summary>
/// 处理授权失败的请求
/// </summary>
/// <param name="actionContext"></param>
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
var erModel = new HttpResult()
{
Success = false,
Message = "身份认证不正确!"
};
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, erModel, "application/json");
}
}
4.5在StudentController中添加过滤属性ApiAuthorize
具体如下:
[RoutePrefix("api/Student"),ApiAuthorize]
public class StudentController : ApiController
{
private static readonly List<Student> StudentList = new List<Student>()
{
new Student() {Id = "001", Name = "张三", Sex = "男", Age = 19, Dept = "软件学院"},
new Student() {Id = "002", Name = "李丽", Sex = "女", Age = 19, Dept = "资环学院"}
};
[HttpGet]
public IEnumerable<Student> Get()
{
return StudentList;
}
[HttpGet, Route("GetByDept/{dept}")]
public IEnumerable<Student> GetByDept(string dept)
{
List<Student> tempList = StudentList.Where(p => p.Dept == dept).ToList();
return tempList;
}
[HttpGet]
public Student Get(string id)
{
List<Student> tempList = StudentList.Where(p => p.Id == id).ToList();
return tempList.Count == 1 ? tempList.First() : null;
}
[HttpPost]
public bool Post([FromBody] Student student)
{
if (student == null) return false;
if (StudentList.Where(p => p.Id == student.Id).ToList().Count > 0) return false;
StudentList.Add(student);
return true;
}
[HttpPut]
public bool Put(string id, [FromBody] Student student)
{
if (student == null) return false;
List<Student> tempList = StudentList.Where(p => p.Id == id).ToList();
if (tempList.Count == 0) return false;
Student originStudent = tempList[0];
originStudent.Name = student.Name;
originStudent.Sex = student.Sex;
originStudent.Age = student.Age;
originStudent.Dept = student.Dept;
return true;
}
[HttpDelete]
public bool Delete(string id)
{
List<Student> tempList = StudentList.Where(p => p.Id == id).ToList();
if (tempList.Count == 0) return false;
StudentList.Remove(tempList[0]);
return true;
}
}
依照步骤添加相关代码,此时就完成了JWT验证的添加。
5.通过PostMan测试程序
运行VS,查看相关API接口,如下图所示。
登录前,测试Get:http://localhost:44321/api/Student
接口,返回结果如下图所示。
登录,测试Post:http://localhost:44321/api/System/Login
接口,返回结果如下图所示。
登录后,测试Get:http://localhost:44321/api/Student
接口,返回结果如下图所示。
在APIController上添加权限验证后,访问相应接口时,需要在header里面添加auth属性(token),这样就完成了身份认证。
6.总结
本文介绍了JWT的原理,然后通过代码完成了相应实例教程,博文中的源代码可以通过笔者GitHUb获取。博文写作不易希望多多支持,后续会更新更多内容,感兴趣的朋友可以加关注,欢迎留言交流!也可以通过微信公众搜索“码探长”,联系笔者!
扫描添加下方的微信公众号,获取更多福利和干货!也可通公众号(码探长)联系探长,期待与你相遇!!!
ASP.NET Web API 2系列(四):基于JWT的token身份认证方案的更多相关文章
- 基于JWT的token身份认证方案
一.使用JSON Web Token的好处? 1.性能问题. JWT方式将用户状态分散到了客户端中,相比于session,可以明显减轻服务端的内存压力. Session方式存储用户id的最大弊病在于S ...
- 基于JWT的token身份认证方案(转)
https://www.cnblogs.com/xiangkejin/archive/2018/05/08/9011119.html 一.使用JSON Web Token的好处? 1.性能问题. JW ...
- ASP.NET Web API实践系列04,通过Route等特性设置路由
ASP.NET Web API路由,简单来说,就是把客户端请求映射到对应的Action上的过程.在"ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置"一 ...
- ASP.NET Web API实践系列07,获取数据, 使用Ninject实现依赖倒置,使用Knockout实现页面元素和视图模型的双向绑定
本篇接着上一篇"ASP.NET Web API实践系列06, 在ASP.NET MVC 4 基础上增加使用ASP.NET WEB API",尝试获取数据. 在Models文件夹下创 ...
- ASP.NET Web API实践系列05,消息处理管道
ASP.NET Web API的消息处理管道可以理解为请求到达Controller之前.Controller返回响应之后的处理机制.之所以需要了解消息处理管道,是因为我们可以借助它来实现对请求和响应的 ...
- ASP.NET Web API 2系列(三):查看WebAPI接口的详细说明及测试接口
引言 前边两篇博客介绍了Web API的基本框架以及路由配置,这篇博客主要解决在前后端分离项目中,为前端人员提供详细接口说明的问题,主要是通过修改WebApi HelpPage相关代码和添加WebAp ...
- ASP.NET WebApi 基于JWT实现Token签名认证
一.前言 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NET WebServi ...
- .NetCore WebApi——基于JWT的简单身份认证与授权(Swagger)
上接:.NetCore WebApi——Swagger简单配置 任何项目都有权限这一关键部分.比如我们有许多接口.有的接口允许任何人访问,另有一些接口需要认证身份之后才可以访问:以保证重要数据不会泄露 ...
- 基于JWT的Token身份验证
身份验证,是指通过一定的手段,完成对用户身份的确认.为了及时的识别发送请求的用户身份,我们调研了常见的几种认证方式,cookie.session和token. 1.Cookie cookie是 ...
随机推荐
- springMVC入门(三)------springMVC的处理器映射器和处理器适配器配置
简介 springMVC的处理器映射器和处理器适配器存在多种配置,因此在此专门做一个总结 常见处理器映射器.适配器的配置 springmvc多个映射器多个处理器可以并存 所有的映射器都实现了Handl ...
- Docker-Docker容器跨主机通信
Docker默认的网络环境下,单台主机上的Docker容器可以通过docker0网桥直接通信,而不同主机上的Docker容器之间只能通过在主机上做端口映射进行通信.这种端口映射方式对很多集群应用来说极 ...
- PyTorch学习笔记及问题处理
1.torch.nn.state_dict(): 返回一个字典,保存着module的所有状态(state). parameters和persistent_buffers都会包含在字典中,字典的key就 ...
- python 列表和字典的引用与复制(copy)
列表或字典的引用: 引用针对变量的时候,传递引用后,对引用后的对象的值进行改变是不会影响到原值的:而列表不一样如: spam =42 cheese = spam spam =100 print(spa ...
- Java中的判断实例
.getClass().getName() 这是最常见的一种判断类型的方法 instanceof 用于判断 对象 是否为某个类的实例 Boolean值 各种is方法 isAnnotationPrese ...
- 学习seo技术要不断地扩大思维和思路
http://www.wocaoseo.com/thread-148-1-1.html 目前学习seo技术的人员是越来越多了,通过查看seo这个词的指数,就能发现一些状况,从最初的每天3 ...
- 力扣Leetcode 199. 二叉树的右视图
199. 二叉树的右视图 给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值. 示例: 输入: [1,2,3,null,5,null,4] 输出: [1, 3, ...
- linux系统工程师修改打开文件数限制代码教程。服务器运维技术
提示linux文件打开错误,修改linux打开文件数参数. /etc/pam.d/login 添加 session required /lib/security/pam_limits.so 注意看这个 ...
- mysql必知必会——GROUP BY和HAVING
mysql必知必会——GROUP BY和HAVING 创建表结构 create table `employ_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, ...
- P3311 [SDOI2014]数数 AC自动机+数位DP
题意 给定一个正整数N和n个模式串,问不大于N的数字中有多少个不包含任意模式串,输出对\(1e^9+7\)取模后的答案. 解题思路 把所有模式串都加入AC自动机,然后跑数位DP就好了.需要注意的是,这 ...