JWT实战
JWT实战
JWT认证流程
先来回顾下JWT的流程,jwt是存储在客户端的,服务器不需要存储jwt;客户端每次发送请求时携带token,然后到服务端验证token是否正确,是否过期,然后解码出携带的用户信息。
存在的问题
1、Token失效问题:
比如在浏览器端通过用户名/密码验证获得签名的Token被木马窃取。即使用户登出了系统,黑客还是可以利用窃取的Token模拟正常请求可用它访问服务器,而服务器端对此完全不知道,(因为JWT机制是无状态的),直到过期,中间服务器无法控制它.
2、 app类Token的有效时间
token的有效时间:
1. 如果 app 是新闻类/游戏类/聊天类等需要长时间用户粘性的. 一般可以设置1年的有效时间!
2. 如果 app 是 支付类/银行类的. 一般token只得有效时间比较短: 15分钟左右!
- 1
- 2
- 3
- 4
- 5
- 6
我们的解决方法是:
服务端使用Redis缓存服务器签发给已登录用户的Token,
每次客户端发送请求时到redis中查该用户 请求的token 和 redis存的token是否一致,不一致不允许token登录,
如果一致,判断这个token是否可以用(主要防止修改密码和注销操作的token没失效问题)
最后返回用户信息
当用户修改密码和注销时直接将redis中该用户的Token设置失效。下次通过token登录,会提醒token失效,要重新登录,我们重新生成一个新的token给用户。通过redis存储token,实现主动控制 token过期失效的问题了。
封装的JWT工具类 部分代码
生成Token码
/**
* 生成jwt token
* @param userId
* @param expireTime 过期时间戳
* @return
*/
public static String makeToken(String userId,Date expireTime){
long nowMillis = System.currentTimeMillis();
Date now=new Date(nowMillis);//签发时间精度:毫秒
try {
Algorithm algorithm = Algorithm.HMAC256(MyConstance.JWT_SECRET);
return JWT.create().withIssuer(userId).withIssuedAt(now).withExpiresAt(expireTime).sign(algorithm);
} catch (UnsupportedEncodingException exception){
exception.printStackTrace();
} catch (JWTCreationException exception){
exception.printStackTrace();
}
return null;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
解码和验证Token码
/**
* 校验toekn是否有效
* @param userId
* @param token
* @return
*/
public static boolean verifyToken(String userId,String token){
boolean active = true;
try {
Algorithm algorithm = Algorithm.HMAC256(MyConstance.JWT_SECRET);//声明签名所用的算法和秘钥
JWTVerifier verifier = JWT.require(algorithm).withIssuer(userId).build();
verifier.verify(token);
} catch (TokenExpiredException exception){
//System.out.println("--- token 过期");
active = false;
} catch (JWTDecodeException exception){
//System.out.println("--- token 无效");
active = false;
} catch (UnsupportedEncodingException exception){
//System.out.println("--- token 无效");
active = false;
} catch (JWTVerificationException exception){
//System.out.println("--- token 错误");
active = false;
}
return active;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
登录
@ApiOperation(value = "登录")
@RequestMapping(value = "/loginWEB", method = RequestMethod.POST)
public ResponseEntity<BaseResult> loginWEB(HttpServletRequest request, HttpServletResponse response,
@ApiParam("用户名") @RequestParam(value = "username", required = false) String username,
@ApiParam("密码") @RequestParam(value = "password", required = false) String password) {
XkbbUser user=userService.getBy("username", username);
//账号密码校验业务
if(user==null) {
return buildFailedInfo(ApiConstance.USER_NOT_EXIST);
}
if(!password.equals(user.getPassword())) {
return buildFailedInfo(ApiConstance.PASSWORD_ERROR);
}
//获取用户id
String userId=user.getId();
//设置token过期时间为30天之后
Date expireTime = Tool.datePlu(new Date(), 30);
//生成JWT(JSon Web Token)
String token=TokenUtil.makeToken(userId, expireTime);
//更新缓存里面该用户的token:
// 如果已登录,则使其Token失效
TokenUtil.updateTokenAPP(userId, token);
Map<String, Object> map = new HashMap<String, Object>();
map.put("token", token);//服务器生成的token
return buildSuccessInfo(map);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
MyConstance类部分全局常量定义
/**
* token的缓存map名
*/
public static final String KEY_TOKEN_MAP = “key_token_map”;
/**
* JWT生成token时加密用的secret
*/
public static final String JWT_SECRET = “3MZq0BYyGcXYoXjhS4QbAM+2YdlLCwKRr2gvVJOJ”;
/**
* 用户登录校验
* @param userId
* @param token
* @return
*/
//到redis中查该用户 请求的token 和 redis存的token是否一致,不一致不允许token登录,
//再次根据创建时间,判断这个token是否可以用(主要防止出现修改密码和注销操作的token没失效问题)
//失效则Redis中删除该token
public static boolean isLogin(String userId,String token){
if(Tool.isNotBlank(userId)) {
if(Tool.isNotBlank(token)) {
//到redis中查该用户 请求的token 和 redis存的token是否一致,不一致不允许token登录
String existValue = (String) CacheUtil.hget(MyConstance.KEY_TOKEN_MAP, userId);
//System.out.println("existValue:"+existValue);
if(Tool.isNotBlank(existValue) && existValue.equals(token)) {
//再次根据创建时间,判断这个token是否可有效(主要防止出现修改密码和注销操作的token没失效问题)
boolean isLogin = verifyToken(userId,token);
//失效则Redis中删除该token
if(!isLogin){
CacheUtil.hdel(MyConstance.KEY_TOKEN_MAP,userId);
}
return isLogin;
}
}
}
return false;
}
/**
* 清除用户缓存token
* @param userId
* @return
*/
public static String clearToken(String userId){
CacheUtil.hdel(MyConstance.KEY_TOKEN_MAP, userId);
}
/**
* 更新用户token
* @param userId
* @param value
*/
public static void updateToken(String userId,String value){
clearToken(userId);//清除缓存中旧的Token
CacheUtil.hset(MyConstance.KEY_TOKEN_MAP, userId, value);//缓存新的Token
}
JWT实战的更多相关文章
- 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_4-3.登录检验JWT实战之封装通用方法
笔记 3.登录检验JWT实战之封装通用方法 讲解:引入相关依赖并开发JWT工具类 1.加入相关依赖 <!-- JWT相关 --> <dependenc ...
- JWT实战:使用axios+PHP实现登录认证
上一篇文中,我们学习了什么是JWT(Json Web Token),今天我们来结合实例给大家讲述JWT的实战应用,就是如何使用前端Axios与后端PHP实现用户登录鉴权认证的过程. 查看演示 下载源码 ...
- JWT 实战
上一篇我们讲解了 JWT 的基本原理和结构 你了解JWT吗?,接下来我们具体实战一下! 1. 引入依赖 <!--引入jwt--> <dependency> <groupI ...
- SpringBoot整合JWT实战详解
jwt 介绍就不多说了,下面通过代码演示开发过程中jwt 的使用. (1)在pom.xml中引入对应的jar <dependency> <groupId>io.jsonwebt ...
- 基于JWT(Json Web Token)的ASP.NET Web API授权方式
token应用流程 初次登录:用户初次登录,输入用户名密码 密码验证:服务器从数据库取出用户名和密码进行验证 生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT 返还JWT ...
- jwt揭秘(含源码示例和视频)
JSON Web Tokens,是一种开发的行业标准 RFC 7519 ,用于安全的表示双方之间的声明.目前,jwt广泛应用在系统的用户认证方面,特别是现在前后端分离项目. 1. jwt认证流程 在项 ...
- jwt揭秘(含源码示例)
JSON Web Tokens,是一种开发的行业标准 RFC 7519 ,用于安全的表示双方之间的声明.目前,jwt广泛应用在系统的用户认证方面,特别是现在前后端分离项目. 1. jwt认证流程 ...
- 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_汇总
2018年Spring Boot 2.x整合微信支付在线教育网站高级项目实战视频课程 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_1-1.SpringBoot整合微信支付开发在 ...
- 什么是JWT(Json Web Token)
什么是 JWT (Json Web Token) 用户认证是计算机安全领域一个永恒的热点话题. JWT 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519). 该to ...
随机推荐
- 20165234 《Java程序设计》第四周学习总结
第四周学习总结 教材学习内容总结 第5章 子类与继承 子类的继承性 子类和父类在同一包中的继承性:子类继承父类中不是 private 的成员变量和方法作为自己的成员变量和方法 子类和父类不在同一包中的 ...
- sonar排除实体类配置
sonar覆盖率检查可以将一些实体类排除,maven项目可以在pom.xml文件中添加如下配置 <properties> <sonar.exclusions> src/main ...
- 关于Vue的两层for循环
vue的核心功能是for循环,双层for循环的场景也是比较常见. <script type="text/javascript"> var vm = new Vue({ ...
- [转]python3之日期和时间
转自:https://www.cnblogs.com/zhangxinqi/p/7687862.html#_label6 阅读目录 1.python3日期和时间 2.时间元组 3.获取格式化的时间 4 ...
- [转]python3之paramiko模块(基于ssh连接进行远程登录服务器执行命令和上传下载文件的功能)
转自:https://www.cnblogs.com/zhangxinqi/p/8372774.html 阅读目录 1.paramiko模块介绍 2.paramiko的使用方法 回到顶部 1.para ...
- 关于nginx服务器上传限制
nginx的上传参数问题,需要特别注意client_max_body_size这个参数,否则会中断在nginx的请求中,在php中无法log到访问的.修改了php.ini文件如下:参数 设置 说明fi ...
- Laravel 5.2数据库--填充数据
1.简介 Laravel 包含了一个简单方法来填充数据库——使用填充类和测试数据.所有的填充类都位于database/seeds目录.填充类的类名完全由你自定义,但最好还是遵循一定的规则,比如可读性, ...
- python-元类的几种单例模式
单例介绍: 单例即单个的实例,指的是同一个类实例化多次的结果都是指向同一个对象,用于节省内存空间 如果我们从配置文件中读取配置信息来进行实例化,在配置相同的情况下,就没必要重复产生对象浪费内存了. # ...
- css中input框不可点击+首行缩进
Css 1)text-indent::首行缩进 2)disabled="true"设置input框不可以点击 3)Css:xx!important:声明提前优先级最高..!impo ...
- mysql·事务挂起
当开启事务后,程序挂了而事务没有提交,那么会被锁住,报错:连接超时,但不影响查询. 下面操作需要权限 一.查询现在被占用的锁信息 select * from information ...