代码地址如下:
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. BufferedInputStream&BufferedOutputStream

    使用字符缓冲区相关实现copy文件: public static void main(String[] args) { //创建文件对象指定要拷贝的文件路径(源文件),文件须存在,测试用例不做判断 F ...

  2. 【Android开发日记】之入门篇(二)——调试

    程序员有一半的时间花在测试BUG身上,而作为一个程序员遇上BUG是不可避免的事情.所以掌握好调试BUG的技术就显得至关重要.接下来我来讲述调试的几个要点. 一.调试机器的选择(模拟器) eclipse ...

  3. sed 使用总结

    1. 更新区间值 文件的内容如下: <ClientVersion> <Item> <ProductUuid>5fa7d5af-6f6a-4d1f-b773-ac42 ...

  4. Visual Studio 2013下我常用的两个插件

    随手记一下,我比较常用的两个插件,抛砖引玉. 代码高亮显示:SelectionHighlight.vsix 虚线插件:Indent Guides.vsix

  5. Beginning iOS 8 Programming with Swift-TableView

    UITableView控件使用 使用UITableView,在控件库中,拖拽一个Table View到ViewController中,在Controller的后台代码中需要继承UITableViewD ...

  6. luogu P3817 小A的糖果

    题目描述 小A有N个糖果盒,第i个盒中有a[i]颗糖果. 小A每次可以从其中一盒糖果中吃掉一颗,他想知道,要让任意两个相邻的盒子中加起来都只有x颗或以下的糖果,至少得吃掉几颗糖. 输入输出格式 输入格 ...

  7. 分享 | 自定义属于自己的U盘图标

    文章目录 步骤 注意 想不想也可以自定义自己的U盘图标?其实,这并不难 步骤 在网上下载ICO格式的图标,也可以将自己喜欢的图片转换成ICO格式,并将图片命名为demo.ico: 点击这里打开记事本, ...

  8. 无需重新编译php加入ftp扩展的解决方法

    无需重新编译php加入ftp扩展的解决方法   本文为大家介绍无需重新编译php加入ftp扩展的方法,有需要的朋友可以参考下   首先,进入源码目录cd php-5.2.13/ext/ftp #运行p ...

  9. ASIHTTPRequest框架使用总结系列之阿堂教程4(下载数据)

    从本篇开始,阿堂准备进一步介绍ASIHTTPRequest框架下载数据和上传数据的实际应用.        为了实现多线程并发请求网络能力,ASIHTTPRequest被设计成 NSOperation ...

  10. ASIHTTPRequest框架使用总结系列之阿堂教程3(异步请求)

    在上一节中,阿堂和网友们分享了ASIHTTPRequest框架对于get,post的同步请求方式.很显然,如果网速比较慢,查询的时候会一直很黑屏,直到请求结束界面才出现结果,这样用户体验肯定很不好了. ...