/** * @Author Liu Yaofu * @create 2021/7/25 10:24 */ public interface JwtUserService extends IService<JwtUser> { JwtUser login(JwtUser user); }
/** * @Author Liu Yaofu * @create 2021/7/25 10:18 */ @Mapper @Repository public interface JwtUserMapper extends BaseMapper<JwtUser>{ JwtUser login(JwtUser user); }
1.1. Introduction to JWT
JWT (JSON WEB TOKEN): JSON Web Token, JWT is a lightweight secure cross-platform transport format that defines a compact self-contained way to securely transmit information (JSON format) between different entities. It is a standard for transferring data between two entities in a Web environment. What is actually transmitted is a string. In a broad sense, JWT is a standard name; in a narrow sense, JWT refers to the token string used to pass
1.2. What can JWT do?
1. Authorization
This is the most common scenario for using JWT. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services and resources allowed by that token. Single sign-on is a feature where JWT is widely used today because it has little overhead and can be easily used across different domains.
1. Information exchange
JSON Web Token s are a great way to securely transfer information between parties. Because the JWT can be signed (e.g. with a public/private key pair), you can be sure that the sender is who they say they are. Additionally, since the signature is calculated using the header and payload, you can also verify that the content has not been tampered with.
1.3. What is the JWT authentication process?
1.4. What is the structure of JWT?
1.5. Using JWT
1. Generate token
/* @SpringBootTest */ class JwtApplicationTests { //Secret key private static final String SIGN = "QWERTYUIOPKJHGFDSA"; public static final byte[] SECRET = "1234567890qwertyuiopasdfghjklzxcvbnm".getBytes(); /** * create token */ @Test void createToken() { //token expires after 20 seconds Calendar instance = Calendar.getInstance(); instance.add(Calendar.SECOND,60); String token = JWT.create() //The first part: header, can not write, default value .withClaim("userId", "620421199604074511")//Part 2: payload .withClaim("userName", "xiaohei") .withExpiresAt(instance.getTime())//token expiration time .sign(Algorithm.HMAC256(SIGN));//Part 3: Signature System.out.println("Generated token for:"+token); } }
The resulting result is:
2. Parse token
/* @SpringBootTest */ class JwtApplicationTests { //Secret key private static final String SIGN = "QWERTYUIOPKJHGFDSA"; public static final byte[] SECRET = "1234567890qwertyuiopasdfghjklzxcvbnm".getBytes(); /** * Parse token */ @Test void jxToken(){ String token="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHQiOjE2MjczOTc1MzczNjQsInVzZXJOYW1lIjoi5Lyg5p-T55eF5rWL6K-V6LSm5Y-3IiwidXNlcklkIjoiOGE5MmEyOWI3YWFlOWE0MzAxN2FjMWQ5MmRjNTAwMDUiLCJpYXQiOjE2MjczNzU5MzczNjR9.OrfK6_Z8Vw6WconHqYfsIBdt4qAHjcQzdNXKXgvsEuo"; //Create an authentication object JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build(); DecodedJWT decodedJWT = jwtVerifier.verify(token); System.out.println("userId for:"+decodedJWT.getClaim("userId").asString()); System.out.println("userName for:"+decodedJWT.getClaim("userName").asString()); System.out.println("expiresAt for:"+decodedJWT.getExpiresAt()); } }
The result of parsing is:
1.6, package tool class
/** * @Author Liu Yaofu * @create 2021/7/24 10:53 */ public class JWTUtils { //signature key private static final String SIGNATURE = "q#W#%T<!G*H?CVX~HEW^&*"; /** * 1,Generate token header.payload.signature * @return */ public static String getToken(Map<String,String> payload){ Calendar instance = Calendar.getInstance(); instance.add(Calendar.DATE,1); //Create JWT builder JWTCreator.Builder builder = JWT.create(); //Part 2: payload payload.forEach((k,v)->{ builder.withClaim(k,v); }); //Specify token expiration time String token = builder.withExpiresAt(instance.getTime()) //Part 3: Signature .sign(Algorithm.HMAC256(SIGNATURE)); return token; } /** * 2,Verify token illegality\Get token information * @param token */ public static DecodedJWT verifier(String token){ return JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token); } }
1.7, JWT integration SpringBoot
1. Introduce dependencies
<!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- druid data source driven --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.20</version> </dependency> <!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.2</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--swagger--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency>
2,application.yml
server: port: 8989 spring: datasource: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username: root password: '0407' #Aliases, mapper paths, camel case naming rules mybatis: type-aliases-package: com.lyf.jwt.entity mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true
3. Create the database table jwt_user
4. Create Entity
/** * @Author Liu Yaofu * @create 2021/7/25 10:13 */ @Data @Accessors(chain = true) @AllArgsConstructor @NoArgsConstructor @TableName("jwt_user") @ApiModel(value="User object", description="user table") public class JwtUser implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "primary key") @TableId(value = "id", type = IdType.UUID) private String id; @ApiModelProperty(value = "username") @TableField("name") private String name; @ApiModelProperty(value = "password") @TableField("password") private String password; }
5. Create mapper
/** * @Author Liu Yaofu * @create 2021/7/25 10:18 */ @Mapper @Repository public interface JwtUserMapper extends BaseMapper<JwtUser>{ JwtUser login(JwtUser user); }
6. Create service
/** * @Author Liu Yaofu * @create 2021/7/25 10:24 */ public interface JwtUserService extends IService<JwtUser> { JwtUser login(JwtUser user); }
7. Create impl
/** * @Author Liu Yaofu * @create 2021/7/25 10:28 */ @Service @Transactional public class JwtUserServiceImpl extends ServiceImpl<JwtUserMapper, JwtUser> implements JwtUserService { @Autowired private JwtUserMapper jwtUserMapper; @Override public JwtUser login(JwtUser user) { JwtUser dbUser = jwtUserMapper.login(user); if(dbUser!=null){ return dbUser; } throw new RuntimeException("Login failed"); } }
8. Create controller, generate token token, authenticate
/** * @Author Liu Yaofu * @create 2021/7/25 10:36 */ @Slf4j @RestController public class JwtUserController { @Autowired private JwtUserService jwtUserService; @GetMapping("/user/login") public Map<String,Object> login(JwtUser user){ Map<String,Object> map = new HashMap<>(); try{ JwtUser dbUser = jwtUserService.login(user); //Generate token token Map<String,String> payload = new HashMap<>(); payload.put("id", dbUser.getId()); payload.put("name",dbUser.getName()); String token = JWTUtils.getToken(payload); map.put("state",true); map.put("msg","Authentication succeeded"); map.put("token",token); }catch (Exception e){ map.put("state",false); map.put("msg","Login failed"); } return map; } }
Return result:
9. Resource authorization
/** *Authorize the resource token * @param token * @return */ @PostMapping("/user/getInfo") public Map<String,Object> getInfo(String token){ Map<String,Object> map = new HashMap<>(); try{ DecodedJWT verifier = JWTUtils.verifier(token); map.put("id",verifier.getClaim("id").asString()); map.put("name",verifier.getClaim("name").asString()); map.put("state",true); map.put("msg","request succeeded"); return map; }catch (SignatureVerificationException e){ e.printStackTrace(); map.put("msg","invalid signature"); }catch (TokenExpiredException e){ e.printStackTrace(); map.put("msg","token Expired"); }catch (AlgorithmMismatchException e){ e.printStackTrace(); map.put("msg","token Algorithm inconsistency"); }catch (Exception e){ e.printStackTrace(); map.put("msg","invalid signature"); } map.put("state",false); return map; }
Test Results
1.8. Problems caused by small 9 in the above 1.7
Using the above method, the token data must be passed every time, and each method needs to verify the redundancy of the token code. How to optimize it if it is not flexible enough?
Optimizing with Interceptors
1.9, use interceptor for authorization
1. JWT interceptor
/** * 1,JWT interceptor * @create 2021/7/25 11:51 * @Author Liu Yaofu */ public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Map<String,Object> map = new HashMap<>(); //Get the token in the request header String token = request.getHeader("token"); try{ //verification token DecodedJWT verifier = JWTUtils.verifier(token); //release request return true; }catch (SignatureVerificationException e){ e.printStackTrace(); map.put("msg","invalid signature"); }catch (TokenExpiredException e){ e.printStackTrace(); map.put("msg","token Expired"); }catch (AlgorithmMismatchException e){ e.printStackTrace(); map.put("msg","token Algorithm inconsistency"); }catch (Exception e){ e.printStackTrace(); map.put("msg","invalid signature"); } map.put("state",false); //Convert map to json response to the front end String json = new ObjectMapper().writeValueAsString(map); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(json); return false; } }
2. JWT configuration
/**JWT configuration class * 2,intercepted request * @Author Liu Yaofu * @create 2021/7/25 12:23 */ @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { //Add JwtInterceptor interceptor registry.addInterceptor(new JwtInterceptor()) .addPathPatterns("/**")//block all paths .excludePathPatterns("/user/**");//Exclude paths, paths that generate token s are not intercepted } }
So far jwt learning, springboot integration jwt is completed