博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用JWT Token实现WebApi访问验证及用户登录限制
阅读量:4032 次
发布时间:2019-05-24

本文共 6930 字,大约阅读时间需要 23 分钟。

JSON Web Token(JWT)跨域身份验证解决方案,详细说明网上很多,这里不就重点介绍了。

问题:WebApi项目开发完成后部署到服务器后WebApi方法任何人都可以调用,有些项目肯定是不允许的,也过不了安全审计。那如何解决呢,这里介绍一种使用JWT 产生Token,为每个方法加一个Token的身份验证,这样,用户在正常登录后,获取到系统为该用户产生的Token,以后,每次调用服务端的WebApi方法时,都需要把这个Token送到服务端做验证,只有正确的Token,才能访问,否则,服务端返回异常。同时,还可以通过这个Token来限制登录,同一时间,相同的用户,只允许存在一个有效用户。关于产生的Token如何存储,或者不存储也可以,这要看具体业务场景了,具体事情具体分析,本文主要是通过示例介绍一种思路,文中示例客户端使用Cookie存储,服务端使用了Redis。下面还是上代码吧。

开发工具:VS2015 

软件环境:redis

必需工具:

在需要加Token验证的webapi项目中加jwt.dll的引用

同时也把redisclient项目引用进来,可以上git hub下载。

然后新增一个用产生和验证Token的类JwtHelper

using System;using System.Collections.Generic;using System.Linq;using System.Web;using Newtonsoft.Json.Linq;using JWT;using JWT.Algorithms;using JWT.Serializers;using JWT.Exceptions;using CSRedis;namespace JwtToken{    public class JwtHelper    {        private const string secret = "scott";        public static string GenerateToken(string userCode)        {            try            {                IDateTimeProvider provider = new UtcDateTimeProvider();                var now = provider.GetNow();                var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); // or use JwtValidator.UnixEpoch                var secondsSinceEpoch = Math.Round((now - unixEpoch).TotalSeconds);                //3分钟后失效                var payload = new Dictionary
{ { "user",userCode}, { "exp",secondsSinceEpoch+ 60*3 }, { "jti",Guid.NewGuid() } }; IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); IJsonSerializer serializer = new JsonNetSerializer(); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder); var token = encoder.Encode(payload, secret); return token; } catch { return ""; } } public static string VerifyToken(string Token) { string result = ""; try { IDateTimeProvider provider = new UtcDateTimeProvider(); IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); IJsonSerializer serializer = new JsonNetSerializer(); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtValidator validator = new JwtValidator(serializer, provider); IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm); var json = decoder.Decode(Token, secret, verify: true);//token为之前生成的字符串 JObject jobj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(json); string userCode = jobj["user"].ToString(); RedisClient redis = new RedisClient("192.168.197.132", 6379); string originalToken = redis.Get(userCode); if(!Token.Equals(originalToken)) { result = "该帐号在其它地方登录"; } } catch (TokenExpiredException) { result = "Token 过期"; } catch (SignatureVerificationException) { result = "Token 不正确"; } catch (Exception ex) { result = "Token 验证出错"; } return result; } }}

 然后在登录方法中,加入

string _token = JwtHelper.GenerateToken(登录ID);

将用户编码加到Token中,Token生成成功后,将该用户编码的Token存入redis并返回客户端,这里推荐将Token放入header中返加,而不是放在json中返回,放json中,容易被中途截获。

httpResponseMessage.Headers.Add("Authorization", _token);

header中的token数据

客户端在收到登录验证通过的信息后,从header中取出token保存到cookie中

$.ajax({            url: "/api/Login/CheckLogin",            type: "Post",            contentType: "application/json",            dataType: "json",            data: JSON.stringify(objPara),            success: function (data, textStatus, jqXHR) {                $.cookie("Authorization", jqXHR.getResponseHeader("Authorization"), { expires: 1, path: '/' });                            },            error: function (XMLHttpRequest, textStatus, errorThrown) {                            }        });

$.cookie("Authorization", jqXHR.getResponseHeader("Authorization"), { expires: 1, path: '/' })

这句代码就是通过jqXHR.getResponseHeader("Authorization")获取header上的token后保存到cookie("Authorization")中,有效时间1天,所有页面均可访问。现在用户已经获得有效Token,接下来,每访问一次webapi,都要将该token发送给服务端,然后验证。接下来有两步工作要做,发送和验证,先说发送,服务端通过header把token送过来,那客户端也应该是通过header将token送过去,先把刚存在cookie中的token取出来

var token = $.cookie("Authorization");

然后在ajax调用中加入headers的参数,如下图。

这样,token就包含在header上,被送到了服务端。

接下来,服务端如何进行验证,这部分是个重点。在这之前,先借用一下网上的一个解释说明一下,有助于理解验证方法。

将生成的Token发送给客户端后,随后,客户端的每次请求只需带上这个Token即可

一般都是将Token存放在Http请求的Headers中,也就是:context.Request.Headers,那么如何接收请求头中的Token呢?接收到Token后如何验证呢?

验证TOKEN时就需要构建 MVC Action 过滤器(AuthorizeAttribute)了,不过在构建 AuthorizeAttribute 之前,有必要对 AuthorizeAttribute 说明下,如下:

首先,AuthorizeAttribute 类位于System.Web.Http 命名空间下及System.Web.Mvc命名空间下,

一般情况下,如果你需要对C# MVC 控制器的访问作认证与授权,你需要用System.Web.Mvc命名空间下的 AuthorizeAttribute ,如果你需要对C# API 控制器的访问作认证与授权,你需要用System.Web.Http 命名空间下的 AuthorizeAttribute !

看完这个解释,接下来,需要新建一个验证属性类ApiTokenCheck,这里只针对webapi方法验证,所以类继承自System.Web.Http.AuthorizeAttribute

using System;using System.Collections.Generic;using System.Linq;using System.Net.Http;using System.Web;using System.Web.Http;using System.Web.Http.Controllers;namespace JwtToken{    public class ApiTokenCheck : AuthorizeAttribute    {        public override void OnAuthorization(HttpActionContext context)        {            var authHeader = context.Request.Headers.FirstOrDefault(a => a.Key == "Authorization");//获取接收的Token            if (context.Request.Headers == null)            {                context.Response = context.Request.CreateErrorResponse(System.Net.HttpStatusCode.Unauthorized, new HttpError("Token 不正确"));            }            if(!context.Request.Headers.Any())            {                context.Response = context.Request.CreateErrorResponse(System.Net.HttpStatusCode.Unauthorized, new HttpError("Token 不正确"));            }            if(authHeader.Key == null)            {                context.Response = context.Request.CreateErrorResponse(System.Net.HttpStatusCode.Unauthorized, new HttpError("Token 不正确"));            }            var token = authHeader.Value.FirstOrDefault();            string Verify = JwtHelper.VerifyToken(token);            if(Verify != "")            {                context.Response = context.Request.CreateErrorResponse(System.Net.HttpStatusCode.Unauthorized, new HttpError(Verify));            }                    }    }}

建好后,在需要进行验证的webapi方法加上验证属性即可

加了[ApiTokenCheck]的方法被请求调用时,都会先触发OnAuthorization方法进行验证,验证不通过通过下列代码返回异常信息给浏览器

context.Response = context.Request.CreateErrorResponse(System.Net.HttpStatusCode.Unauthorized, new HttpError(Verify));

OK,到这里,token生成,保存,发送,接收,验证 ,验证结果返回这个流程就结束了。

如有描述不清楚的地方,也可以直接看代码。

本文代码位置:

转载地址:http://cgqbi.baihongyu.com/

你可能感兴趣的文章
如何优雅的编程,lombok你怎么这么好用
查看>>
@RequestParam、@QueryParam等Spring常见参数注解区别,你知道吗
查看>>
玩转远程Debug,两步轻松开启IDEA远程调试
查看>>
Jmeter压测错误,Address already in use: connect
查看>>
Intellij IDEA常用快捷键,最全总结
查看>>
前端干货,超实用的JQuery小技巧
查看>>
Spring Boot 几个常见的核心注解
查看>>
程序员需要懂的一些Linux基本命令
查看>>
程序员需要掌握的一些网络协议汇总
查看>>
搞定Windows下的Hadoop环境安装
查看>>
设计模式之单例模式的五种写法
查看>>
Nginx开启Gzip压缩,使你的网页急速加载
查看>>
一文看清HBase的使用场景
查看>>
除了负载均衡,Nginx还可以做很多,限流、缓存、黑白名单
查看>>
解析zookeeper的工作流程
查看>>
搞定Java面试中的数据结构问题
查看>>
深入理解Apache Flink核心技术
查看>>
SpringCloud 各组件原理图,面试必备
查看>>
面试题总结:可能是全网最好的MySQL重要知识点
查看>>
MySQL面试之数据库索引
查看>>