基于JWT的Token开发案例
0、准备工作
0-1运行环境
- jdk1.8
- maven
- 一个能支持以上两者的代码编辑器,作者使用的是IDEA。
0-2知识储备
- 对SpringBoot框架有所了解
- 对token的定义有了解
- 本案例简单,代码注释较少,有不明白的地方,或者不正确的地方,欢迎联系作者本人或留言。
1、设计思路
1-1 项目结构
本案例模拟用户登录/注册后,服务器返回一个token用于用户后续操作。
/controller/HelloController.java:测试token的接口
/controller/UserController.java:用户注册/登录的接口
/entity/User.java:用户实体类,属性有 用户ID,用户名,密码,邮箱,上次登录时间。
/repository/UserRepository:实现SpringData接口的数据库操作类,可以很方便的进行CRUD等操作。
/Reponse/UserResponse.java:接口返回数据的实体类。
/util/Constants.java:存放常量的工具类。
/util/JwtUtil.java:Jwt工具类,可以生成、解析Jwt。
1-2 实现难点
- 对Jwt的理解,可以参考http://blog.leapoahead.com/2015/09/06/understanding-jwt/
- JwtUtil工具类的开发
2 具体实现
2-1 JwtUtil.java
@Component
public class JwtUtil {
private static UserRepository userRepository;
@Autowired
public JwtUtil(UserRepository userRepository) {
JwtUtil.userRepository = userRepository;
}
public static final long EXPIRATION_TIME = 3600_000_000L; // 1000 hour
static final String SECRET = "ThisIsASecret";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";
public static String generateToken(String username,Date generateTime) {
HashMap<String, Object> map = new HashMap<>();
//可以把任何安全的数据放到map里面
map.put("username", username);
map.put("generateTime",generateTime);
String jwt = Jwts.builder()
.setClaims(map)
.setExpiration(new Date(generateTime.getTime() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
return jwt;
}
/**
* @param token
* @return
*/
public static Map<String,Object> validateToken(String token) {
Map<String,Object> resp = new HashMap<String,Object>();
if (token != null) {
// 解析token
try {
Map<String, Object> body = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
.getBody();
String username = (String) (body.get("username"));
Date generateTime = new Date((Long)body.get("generateTime"));
if(username == null || username.isEmpty()){
resp.put("ERR_MSG",Constants.ERR_MSG_USERNAME_EMPTY);
return resp;
}
//账号在别处登录
if(userRepository.findByUsername(username).getLastLoginTime().after(generateTime)){
resp.put("ERR_MSG",Constants.ERR_MSG_LOGIN_DOU);
return resp;
}
resp.put("username",username);
resp.put("generateTime",generateTime);
return resp;
}catch (SignatureException | MalformedJwtException e) {
// TODO: handle exception
// don't trust the JWT!
// jwt 解析错误
resp.put("ERR_MSG",Constants.ERR_MSG_TOKEN_ERR);
return resp;
} catch (ExpiredJwtException e) {
// TODO: handle exception
// jwt 已经过期,在设置jwt的时候如果设置了过期时间,这里会自动判断jwt是否已经过期,如果过期则会抛出这个异常,我们可以抓住这个异常并作相关处理。
resp.put("ERR_MSG",Constants.ERR_MSG_TOKEN_EXP);
return resp;
}
}else {
resp.put("ERR_MSG",Constants.ERR_MSG_TOKEN_EMPTY);
return resp;
}
}
}
2.2 UserController.java
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserRepository userRepository;
//注册或登录
@RequestMapping("/login")
@Transactional
public UserResponse login(User user){
String username = user.getUsername();
String password = user.getPassword();
//TODO 检验参数的完整性
UserResponse userResponse = new UserResponse();
User tUser = userRepository.findByUsername(username);
//检验username是否存在
user.setLastLoginTime(new Date());
if(tUser!=null){
//检验密码是否正确
if(!tUser.getPassword().equals(password)) {
userResponse.setErrorNum(Constants.ERR_NUM_PWD_ERR);
userResponse.setErrorMsg(Constants.ERR_MSG_PWD_ERR);
return userResponse;
}
userRepository.updateLastLoginTimeByUserName(user.getLastLoginTime(),username);
}else {
try {
tUser = userRepository.save(user);
} catch (Exception e) {
userResponse.setErrorNum(Constants.ERR_NUM_SERVER_ERR);
userResponse.setErrorMsg(Constants.ERR_MSG_SERVER_ERR);
return userResponse;
}
}
userResponse.setErrorNum(Constants.ERR_NUM_OK);
userResponse.setErrorMsg(Constants.ERR_MSG_OK);
userResponse.setUserName(username);
userResponse.setUserId(tUser.getId());
userResponse.setToken(JwtUtil.generateToken(username,user.getLastLoginTime()));
return userResponse;
}
}
2.3 HelloController.java
@RestController
public class HelloController {
@RequestMapping("/hello")
public Map login(HttpServletRequest request){
String token = request.getParameter("token");
return JwtUtil.validateToken(token);
}
}
2.4测试
用户登录后,会返回一串token,咱们可以用token进行下一步请求:
当我再次访问登录接口之后,却用旧的token访问测试接口时:
3 总结
上面是贴出的主要代码,完整的请下载demo包,有不明白的地方请在下方评论,或者联系邮箱yaoyunxiaoli@163.com。
我是妖云小离,这是我第二次在Demo大师上发文章,感谢阅读。
基于JWT的Token开发案例
注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权
基于JWT的Token开发案例的更多相关文章
- ASP.NET WebApi 基于JWT实现Token签名认证
一.前言 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NET WebServi ...
- token 与 基于JWT的Token认证
支持跨域访问,无状态认证 token特点 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输 无状态(也称:服务端可扩展行): ...
- 基于JWT的Token认证机制及安全问题
[干货分享]基于JWT的Token认证机制及安全问题 https://bbs.huaweicloud.com/blogs/06607ea7b53211e7b8317ca23e93a891
- ASP.NET Web API 2系列(四):基于JWT的token身份认证方案
1.引言 通过前边的系列教程,我们可以掌握WebAPI的初步运用,但是此时的API接口任何人都可以访问,这显然不是我们想要的,这时就需要控制对它的访问,也就是WebAPI的权限验证.验证方式非常多,本 ...
- 基于JWT的Token身份验证
身份验证,是指通过一定的手段,完成对用户身份的确认.为了及时的识别发送请求的用户身份,我们调研了常见的几种认证方式,cookie.session和token. 1.Cookie cookie是 ...
- 基于JWT实现token验证
JWT的介绍 Json Web Token(JWT)是目前比较流行的跨域认证解决方案,是一种基于JSON的开发标准,由于数据是可以经过签名加密的,比较安全可靠,一般用于前端和服务器之间传递信息,也可以 ...
- iOS 开发之基于JWT的Token认证机制及解析
在移动端和服务端通信中,一般有两种认证方式:token 和 session. 1.session/cookie 认证机制: 在服务端创建一个Session对象,同时在客户端的浏览器端创建一个Cooki ...
- 基于jwt的token验证
一.什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519). 该token被设计为紧凑且安全的,特别适用于分布 ...
- 基于JWT的token身份认证方案
一.使用JSON Web Token的好处? 1.性能问题. JWT方式将用户状态分散到了客户端中,相比于session,可以明显减轻服务端的内存压力. Session方式存储用户id的最大弊病在于S ...
随机推荐
- openGL深度缓冲区问题
http://zhidao.baidu.com/question/368299839.html&__bd_tkn__=6aa9196c746cd3357f1eec74aeb127b395029 ...
- python 的requests如何使用代理
headers.py import random first_num = random.randint(55, 62) third_num = random.randint(0, 3200) four ...
- UVALive 3507:Keep the Customer Satisfied(贪心 Grade C)
VJ题目链接 题意: 知道n(n <= 8e6)个工作的完成所需时间q和截止时间d,你一次只能做一个工作.问最多能做多少工作? 思路: 首先很像贪心.观察发现如下两个贪心性质: 1)一定存在一个 ...
- python collections(容器)模块
原文:http://docs.pythontab.com/interpy/collections/collections/ 容器(Collections) Python附带一个模块,它包含许多容器数据 ...
- Delphi 7 在程序中直接执行SQL脚本文件
Delphi 7 在程序中直接执行SQL脚本文件 在处理MSDE一些操作中.需要执行一些SQL脚本.有的是从SQLServer 2000中生成的SQL为后缀的脚本.在MSDE中没有企业管理器,操作都是 ...
- Codeforces Round #446 (Div. 2) A. Greed【模拟】
A. Greed time limit per test 2 seconds memory limit per test 256 megabytes input standard input outp ...
- Nginx配置文件分析
#user nobody; #启动进程数,即启动ngnix服务的个数,通常设置和cpu的数量相等 worker_processes 1; #全局错误日志及PID文件 #error_log logs/e ...
- AppScan入门工作原理详解
AppScan,即 AppScan standard edition.其安装在 Windows 操作系统上,可以对网站等 Web 应用进行自动化的应用安全扫描和测试. Rational AppScan ...
- String&&StringBuilder&&StringBuffer
在java中提供三个操作字符串的类:String,StringBuilder,StringBuffer (1)什么是字符串:多个字符的集合 (2)String 是内容不可变的字符串.(底层使用了一个不 ...
- Winform打砖块游戏制作step by step第4节---小球移动
一 引子 为了让更多的编程初学者,轻松愉快地掌握面向对象的思考方法,对象继承和多态的妙用,故推出此系列随笔,还望大家多多支持. 预备知识,无GDI画图基础的童鞋请先阅读一篇文章让你彻底弄懂WinFor ...