代码地址如下:
http://www.demodashi.com/demo/12531.html

0、准备工作

0-1运行环境

  1. jdk1.8
  2. maven
  3. 一个能支持以上两者的代码编辑器,作者使用的是IDEA。

0-2知识储备

  1. 对SpringBoot框架有所了解
  2. 对token的定义有了解
  3. 本案例简单,代码注释较少,有不明白的地方,或者不正确的地方,欢迎联系作者本人或留言。

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 实现难点

  1. 对Jwt的理解,可以参考http://blog.leapoahead.com/2015/09/06/understanding-jwt/
  2. 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开发案例

代码地址如下:
http://www.demodashi.com/demo/12531.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

基于JWT的Token开发案例的更多相关文章

  1. ASP.NET WebApi 基于JWT实现Token签名认证

    一.前言 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NET WebServi ...

  2. token 与 基于JWT的Token认证

    支持跨域访问,无状态认证 token特点 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输 无状态(也称:服务端可扩展行): ...

  3. 基于JWT的Token认证机制及安全问题

    [干货分享]基于JWT的Token认证机制及安全问题 https://bbs.huaweicloud.com/blogs/06607ea7b53211e7b8317ca23e93a891

  4. ASP.NET Web API 2系列(四):基于JWT的token身份认证方案

    1.引言 通过前边的系列教程,我们可以掌握WebAPI的初步运用,但是此时的API接口任何人都可以访问,这显然不是我们想要的,这时就需要控制对它的访问,也就是WebAPI的权限验证.验证方式非常多,本 ...

  5. 基于JWT的Token身份验证

    ​ 身份验证,是指通过一定的手段,完成对用户身份的确认.为了及时的识别发送请求的用户身份,我们调研了常见的几种认证方式,cookie.session和token. 1.Cookie ​ cookie是 ...

  6. 基于JWT实现token验证

    JWT的介绍 Json Web Token(JWT)是目前比较流行的跨域认证解决方案,是一种基于JSON的开发标准,由于数据是可以经过签名加密的,比较安全可靠,一般用于前端和服务器之间传递信息,也可以 ...

  7. iOS 开发之基于JWT的Token认证机制及解析

    在移动端和服务端通信中,一般有两种认证方式:token 和 session. 1.session/cookie 认证机制: 在服务端创建一个Session对象,同时在客户端的浏览器端创建一个Cooki ...

  8. 基于jwt的token验证

    一.什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519). 该token被设计为紧凑且安全的,特别适用于分布 ...

  9. 基于JWT的token身份认证方案

    一.使用JSON Web Token的好处? 1.性能问题. JWT方式将用户状态分散到了客户端中,相比于session,可以明显减轻服务端的内存压力. Session方式存储用户id的最大弊病在于S ...

随机推荐

  1. 编写COOL编译器

    Coursera上面有Stanford的课程“Compilers”,该课程使用“龙书”作为参考书,并有一个编程项目,完成一个完整的编译器.这个编译器支持的语言称为COOL,是一个面向对象的用于教学的语 ...

  2. VS MFC 改变AfxMessageBox标题 AFX_IDS_APP_TITLE

    其实这个标题在资源String Table里就能找到,查找AFX_IDS_APP_TITLE,在这里你就能轻而易举的改变标题了. 注意:有的工程的资源String Table里面没有添加AFX_IDS ...

  3. 查看gcc/g++默认include路径

    转自:http://gcc.gnu.org/ml/gcc-help/2007-09/msg00205.html `gcc -print-prog-name=cc1plus` -v `g++ -prin ...

  4. Scala学习随笔——深入类和对象

    函数化对象(又称方程化对象)指的是所定义的类或对象不包含任何可以修改的状态. 本篇随笔就是着重记录函数化对象.定义了一个有理数类定义的几个不同版本,以介绍 Scala 类定义的几个特性:类参数和构造函 ...

  5. kubernetes 安装(全)

    #http://blog.csdn.net/zhuchuangang/article/details/76572157#https://kubernetes.io/docs/setup/indepen ...

  6. HDU 2602.Bone Collector-动态规划0-1背包

    Bone Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  7. Codeforces 1027F. Session in BSU

    题目直通车:Codeforces 1027F. Session in BSU 思路: 对第一门考试,使用前一个时间,做标记,表示该时间已经用过,并让第一个时间指向第二个时间,表示,若之后的考试时间和当 ...

  8. eleasticsearch重要配置

    elasticsearch重要配置=====================================日志和数据目录-----------------path:    logs: /var/lo ...

  9. Xamarin XAML语言教程Xamarin.Forms中构建进度条

    Xamarin XAML语言教程Xamarin.Forms中构建进度条 ProgressBar被称为进度条,它类似于没有滑块的滑块控件.进度条总是水平放置的.本节将讲解如何使用进度条. 注意:进度条在 ...

  10. [POI2014]Around the world

    题目大意: 一个环上有$n(n\le10^6)$个点,每个点之间的距离为$l_i(l_i\le10^9)$.有$m(m\le100)$架飞机,每架飞机单次最大航行距离为$d_i$.飞机只能在点上起飞. ...