1.什么是jwt

双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快 自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库。
 

2.Jwt在javaweb项目中的简单使用

第一步:引入maven依赖

  1. <!--引入JWT依赖,由于是基于Java,所以需要的是java-jwt-->
  2. <dependency>
  3. <groupId>io.jsonwebtoken</groupId>
  4. <artifactId>jjwt</artifactId>
  5. <version>0.9.1</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>com.auth0</groupId>
  9. <artifactId>java-jwt</artifactId>
  10. <version>3.4.0</version>
  11. </dependency>

第二步:创建两个注解,拦截器通过注释区分是否进行权限拦截(详情参考上一篇文章JWT在JAVAWEB项目中的应用核心步骤解读 https://www.cnblogs.com/jimisun/p/9480886.html)

  1. package com.pjb.springbootjjwt.jimisun;
  2.  
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7.  
  8. @Target({ElementType.METHOD, ElementType.TYPE})
  9. @Retention(RetentionPolicy.RUNTIME)
  10. public @interface LoginToken {
  11. boolean required() default true;
  12. }
  1. package com.pjb.springbootjjwt.jimisun;
  2.  
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7.  
  8. @Target({ElementType.METHOD, ElementType.TYPE})
  9. @Retention(RetentionPolicy.RUNTIME)
  10. public @interface CheckToken {
  11. boolean required() default true;
  12. }

第三步:编写JwtUtil工具类(生成token,解析token,校验token)

  1. package com.pjb.springbootjjwt.jimisun;
  2.  
  3. import io.jsonwebtoken.Claims;
  4. import io.jsonwebtoken.JwtBuilder;
  5. import io.jsonwebtoken.Jwts;
  6. import io.jsonwebtoken.SignatureAlgorithm;
  7.  
  8. import java.util.Date;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. import java.util.UUID;
  12.  
  13. /**
  14. * @Author:jimisun
  15. * @Description:
  16. * @Date:Created in 14:08 2018/8/15
  17. * @Modified By:
  18. */
  19. public class JwtUtil {
  20.  
  21. /**
  22. * 用户登录成功后生成Jwt
  23. * 使用Hs256算法 私匙使用用户密码
  24. *
  25. * @param ttlMillis jwt过期时间
  26. * @param user 登录成功的user对象
  27. * @return
  28. */
  29. public static String createJWT(long ttlMillis, User user) {
  30. //指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。
  31. SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
  32.  
  33. //生成JWT的时间
  34. long nowMillis = System.currentTimeMillis();
  35. Date now = new Date(nowMillis);
  36.  
  37. //创建payload的私有声明(根据特定的业务需要添加,如果要拿这个做验证,一般是需要和jwt的接收方提前沟通好验证方式的)
  38. Map<String, Object> claims = new HashMap<String, Object>();
  39. claims.put("id", user.getId());
  40. claims.put("username", user.getUsername());
  41. claims.put("password", user.getPassword());
  42.  
  43. //生成签名的时候使用的秘钥secret,这个方法本地封装了的,一般可以从本地配置文件中读取,切记这个秘钥不能外露哦。它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
  44. String key = user.getPassword();
  45.  
  46. //生成签发人
  47. String subject = user.getUsername();
  48.  
  49. //下面就是在为payload添加各种标准声明和私有声明了
  50. //这里其实就是new一个JwtBuilder,设置jwt的body
  51. JwtBuilder builder = Jwts.builder()
  52. //如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
  53. .setClaims(claims)
  54. //设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
  55. .setId(UUID.randomUUID().toString())
  56. //iat: jwt的签发时间
  57. .setIssuedAt(now)
  58. //代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可以存放什么userid,roldid之类的,作为什么用户的唯一标志。
  59. .setSubject(subject)
  60. //设置签名使用的签名算法和签名使用的秘钥
  61. .signWith(signatureAlgorithm, key);
  62. if (ttlMillis >= 0) {
  63. long expMillis = nowMillis + ttlMillis;
  64. Date exp = new Date(expMillis);
  65. //设置过期时间
  66. builder.setExpiration(exp);
  67. }
  68. return builder.compact();
  69. }
  70.  
  71. /**
  72. * Token的解密
  73. * @param token 加密后的token
  74. * @param user 用户的对象
  75. * @return
  76. */
  77. public static Claims parseJWT(String token, User user) {
  78. //签名秘钥,和生成的签名的秘钥一模一样
  79. String key = user.getPassword();
  80.  
  81. //得到DefaultJwtParser
  82. Claims claims = Jwts.parser()
  83. //设置签名的秘钥
  84. .setSigningKey(key)
  85. //设置需要解析的jwt
  86. .parseClaimsJws(token).getBody();
  87. return claims;
  88. }
  89.  
  90. /**
  91. * 校验token
  92. * 在这里可以使用官方的校验,我这里校验的是token中携带的密码于数据库一致的话就校验通过
  93. * @param token
  94. * @param user
  95. * @return
  96. */
  97. public static Boolean isVerify(String token, User user) {
  98. //签名秘钥,和生成的签名的秘钥一模一样
  99. String key = user.getPassword();
  100.  
  101. //得到DefaultJwtParser
  102. Claims claims = Jwts.parser()
  103. //设置签名的秘钥
  104. .setSigningKey(key)
  105. //设置需要解析的jwt
  106. .parseClaimsJws(token).getBody();
  107.  
  108. if (claims.get("password").equals(user.getPassword())) {
  109. return true;
  110. }
  111.  
  112. return false;
  113. }
  114.  
  115. }

第四步:编写拦截器拦截请求进行权限验证

  1. package com.pjb.springbootjjwt.interceptor;
  2.  
  3. import com.auth0.jwt.JWT;
  4. import com.auth0.jwt.exceptions.JWTDecodeException;
  5. import com.pjb.springbootjjwt.jimisun.CheckToken;
  6. import com.pjb.springbootjjwt.jimisun.JwtUtil;
  7. import com.pjb.springbootjjwt.jimisun.LoginToken;
  8. import com.pjb.springbootjjwt.jimisun.User;
  9. import com.pjb.springbootjjwt.service.UserService;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.web.method.HandlerMethod;
  12. import org.springframework.web.servlet.HandlerInterceptor;
  13. import org.springframework.web.servlet.ModelAndView;
  14.  
  15. import javax.servlet.http.HttpServletRequest;
  16. import javax.servlet.http.HttpServletResponse;
  17. import java.lang.reflect.Method;
  18.  
  19. /**
  20. * jimisun
  21. */
  22. public class AuthenticationInterceptor implements HandlerInterceptor {
  23.  
  24. @Autowired
  25. UserService userService;
  26.  
  27. @Override
  28. public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
  29.  
  30. // 从 http 请求头中取出 token
  31. String token = httpServletRequest.getHeader("token");
  32. // 如果不是映射到方法直接通过
  33. if (!(object instanceof HandlerMethod)) {
  34. return true;
  35. }
  36.  
  37. HandlerMethod handlerMethod = (HandlerMethod) object;
  38. Method method = handlerMethod.getMethod();
  39. //检查是否有LoginToken注释,有则跳过认证
  40. if (method.isAnnotationPresent(LoginToken.class)) {
  41. LoginToken loginToken = method.getAnnotation(LoginToken.class);
  42. if (loginToken.required()) {
  43. return true;
  44. }
  45. }
  46.  
  47. //检查有没有需要用户权限的注解
  48. if (method.isAnnotationPresent(CheckToken.class)) {
  49. CheckToken checkToken = method.getAnnotation(CheckToken.class);
  50. if (checkToken.required()) {
  51. // 执行认证
  52. if (token == null) {
  53. throw new RuntimeException("无token,请重新登录");
  54. }
  55. // 获取 token 中的 user id
  56. String userId;
  57. try {
  58. userId = JWT.decode(token).getClaim("id").asString();
  59. } catch (JWTDecodeException j) {
  60. throw new RuntimeException("访问异常!");
  61. }
  62. User user = userService.findUserById(userId);
  63. if (user == null) {
  64. throw new RuntimeException("用户不存在,请重新登录");
  65. }
  66. Boolean verify = JwtUtil.isVerify(token, user);
  67. if (!verify) {
  68. throw new RuntimeException("非法访问!");
  69. }
  70. return true;
  71. }
  72. }
  73. return true;
  74. }
  75.  
  76. @Override
  77. public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
  78.  
  79. }
  80.  
  81. @Override
  82. public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
  83.  
  84. }
  85.  
  86. }
配置拦截器(ps:我使用的是springboot,大家使用ssm配置拦截器的方式不一样)

  1. package com.pjb.springbootjjwt.interceptorconfig;
  2.  
  3. import com.pjb.springbootjjwt.interceptor.AuthenticationInterceptor;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  7. import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  8.  
  9. @Configuration
  10. public class InterceptorConfig implements WebMvcConfigurer {
  11.  
  12. @Override
  13. public void addInterceptors(InterceptorRegistry registry) {
  14. registry.addInterceptor(authenticationInterceptor())
  15. .addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
  16. }
  17.  
  18. @Bean
  19. public AuthenticationInterceptor authenticationInterceptor() {
  20. return new AuthenticationInterceptor();
  21. }
  22. }

第五步:在示例Controller中的实际应用

  1. package com.pjb.springbootjjwt.jimisun;
  2.  
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.pjb.springbootjjwt.annotation.PassToken;
  5. import com.pjb.springbootjjwt.annotation.UserLoginToken;
  6. import com.pjb.springbootjjwt.service.UserService;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.web.bind.annotation.*;
  9.  
  10. import javax.validation.Valid;
  11. import java.util.UUID;
  12.  
  13. /**
  14. * @Author:jimisun
  15. * @Description:
  16. * @Date:Created in 15:04 2018/8/15
  17. * @Modified By:
  18. */
  19. @RestController
  20. @RequestMapping("/api")
  21. public class UserController {
  22.  
  23. @Autowired
  24. private UserService userService;
  25.  
  26. //登录
  27. @PostMapping("/login")
  28. @LoginToken
  29. public Object login(@RequestBody @Valid com.pjb.springbootjjwt.jimisun.User user) {
  30.  
  31. JSONObject jsonObject = new JSONObject();
  32. com.pjb.springbootjjwt.jimisun.User userForBase = userService.findByUsername(user);
  33. if (userForBase == null) {
  34. jsonObject.put("message", "登录失败,用户不存在");
  35. return jsonObject;
  36. } else {
  37. if (!userForBase.getPassword().equals(user.getPassword())) {
  38. jsonObject.put("message", "登录失败,密码错误");
  39. return jsonObject;
  40. } else {
  41. String token = JwtUtil.createJWT(6000000, userForBase);
  42. jsonObject.put("token", token);
  43. jsonObject.put("user", userForBase);
  44. return jsonObject;
  45. }
  46. }
  47. }
  48.  
  49. //查看个人信息
  50. @CheckToken
  51. @GetMapping("/getMessage")
  52. public String getMessage() {
  53. return "你已通过验证";
  54. }
  55.  
  56. }
 
 

最后一步,我们现在来访问一下啊

先进行登录

登录后携带token进行业务操作

简单的Demo程序就到这里了,当然还有很多东西没有考虑到,比如jwt在集群环境下的应用等一些问题留到下回探讨啦~

Jwt在Java项目中的简单实际应用的更多相关文章

  1. java项目中ehcache缓存最简单用法

      java项目中ehcache缓存最简单用法: 1.下载ehcache-core-2.4.3.jar复制到项目的lib目录下 2.新建ehcache.xml文件,放置在项目src目录下的resour ...

  2. JAVA项目中公布WebService服务——简单实例

    1.在Java项目中公布一个WebService服务: 怎样公布? --JDK1.6中JAX-WS规范定义了怎样公布一个WebService服务. (1)用jdk1.6.0_21以后的版本号公布. ( ...

  3. 在Java项目中整合Scala

    Scala是一个运行在Java JVM上的面向对象的语言.它支持函数编程,在语法上比Java更加灵活,同时通过Akka库,Scala支持强大的基于Actor的多线程编程.具有这些优势,使得我最近很想在 ...

  4. ckeditor编辑器在java项目中配置

    一.基本使用: 1.所需文件架包 A. Ckeditor基本文件包,比如:ckeditor_3.6.2.zip 下载地址:http://ckeditor.com/download 2.配置使用 A.将 ...

  5. redis在java项目中的使用

    在上一篇文章中已经讲了redis的spring配置,这篇将会描述redis在java项目中的使用. redis存储形式都是key-value(键值对),按照存储的内容分为两种,一种是存简单数据,即数字 ...

  6. Redis学习笔记之二 :在Java项目中使用Redis

    成功配置redis之后,便来学习使用redis.首先了解下redis的数据类型. Redis的数据类型 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set( ...

  7. JAVA项目中常用的异常处理情况总结

    JAVA项目中常用的异常知识点总结 1. java.lang.nullpointerexception这个异常大家肯定都经常遇到,异常的解释是"程序遇上了空指针",简单地说就是调用 ...

  8. Ant在Java项目中的使用(一眼就看会)

    参考:http://www.cnblogs.com/zhengqiang/p/5557155.html Ant是跨平台的构建工具,它可以实现项目的自动构建和部署等功能.在本文中,主要让读者熟悉怎样将A ...

  9. UCenter在JAVA项目中实现的单点登录应用实例

    Comsenz(康盛)的UCenter当前在国内的单点登录领域占据绝对份额,其完整的产品线令UCenter成为了账号集成方面事实上的标准. 基于UCenter,可以将Comsenz旗下的Discuz! ...

随机推荐

  1. atitit。解决 No suitable Log constructor。。NoClassDefFoundError: org/apache/log4j/Category 找不到类的

    atitit.解决 No suitable Log constructor..NoClassDefFoundError: org/apache/log4j/Category 找不到类的 1. 深的层次 ...

  2. Struts2使用OGNL遍历各种map总结

    一.Action中的代码:MapAction.java package com.zx.demo.action; import java.util.ArrayList;   import java.ut ...

  3. php chr() ord()中文截取乱码问题解决方法

    今天看到chr() ord()中文截取乱码问题这个例子,觉得相当的不错,拿出来和大家分享下,有兴趣的朋友可以去试下,看看怎么样. 代码如下: <?php $lenth = ; $str = &q ...

  4. 2、Reactive Extensions for .NET(译)

    实验3-引入 .net 中的 events 到 Rx 目标:前面实验中的使用各种工厂构造方法创建一个 可观察序列是一个部分.把 .net 中现有的异步数据源进行关联 是更重要的事情.在这次实验中我们将 ...

  5. 使用ReaderWriterLock类实现多用户读/单用户写同步

    使用ReaderWriterLock类实现多用户读/单用户写同步[1] 2015-03-12 应用程序在访问资源时是进行读操作,写操作相对较少.为解决这一问题,C#提供了System.Threadin ...

  6. 跟着百度学习php之ThinkPHP的运行流程-2

    Thinkphp为了提高编译的效率,第一次运行的时候thinkphp会把文件全部编译到temp目录下的~runtime.php文件,在第二次运行的时候会直接读取这个文件.所以我们在线下自己写代码测试的 ...

  7. HDU 2110 Crisis of HDU

    Crisis of HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) To ...

  8. Java,Mysql-根据一个给定经纬度的点,进行附近500米地点查询–合理利用算法

    Java,Mysql-根据一个给定经纬度的点,进行附近500米地点查询–合理利用算法   LBS 球面距离公式 http://wiki.myoa.info/zh-blog:20 Java,Mysql- ...

  9. 关于Unity的C#基础学习(五)

    一.get/set访问器 class Person{ int my_age; //默认私有权限 int sex; //属性,类似于函数,但是又不是函数的东西 public int age{ get{ ...

  10. iBATIS SQL Maps

    让我们重回到车辆管理系统和张三的故事中. 在 iBATIS SQL Maps 的世界里也存在 one-to-many.many-to-one 的关系,想必你已经对这些概念驾轻就熟了.好!还是每个 Pe ...