代码地址 https://github.com/kingxiao6317/jwtDemo
一 、依赖
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
二、工具
开发工具:idea
jdk:1.8
系统:win10
三、搭建环境
1. 首先搭建springboot项目, 具体可以参考我的另外一篇文章
2. pom中添加JWT依赖,等待下载依赖包
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
3. 创建JWT中保存数据的类 JwtInfo
可以不用实体直接使用字段传递数据,用实体的话后期扩展比较简单,比如:现在JWT中值保存了用户Id,后期想加入用户名,就可以直接在实体中添加字段,修改对应的代码就行了
import lombok.Data;
import java.io.Serializable;
/**
* JWT中保存的信息
* @author: clx
* @date: 2019/7/22
* @version: 1.1.0
*/
@Data
public class JWTInfo implements Serializable {
/**
* 用户Id
*/
private String userId;
/**
* 用户名字
*/
private String userName;
public JWTInfo(String userId, String userName) {
this.userId = userId;
this.userName = userName;
}
}
4. 创建JWT核心处理类
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;
import org.springframework.stereotype.Component;
/**
* JWT加密解析
* @author: clx
* @date: 2019/7/22
* @version: 1.1.0
*/
@Component
public class JWTHelper {
public static String JWT_SECRET = "JWT_SECRET";
/**
* 密钥加密token 获取token
*
* @param jwtInfo jwt要加密的信息
* @param expire 过期时间 单位/秒
* @return
* @throws Exception
*/
public static String generateToken(JWTInfo jwtInfo, int expire) throws Exception {
String compactJws = Jwts.builder()
.setSubject(jwtInfo.getUserName())
.claim("userId", jwtInfo.getUserId())
.claim("userName", jwtInfo.getUserName())
// 默认7天时间过期
.setExpiration(DateTime.now().plusSeconds((expire == 0 ? 7 : expire)*3600*24).toDate())
// 1天时间过期
// .setExpiration(DateTime.now().plusSeconds(3600*24).toDate())
.signWith(SignatureAlgorithm.HS256, JWT_SECRET.getBytes())
.compact();
return compactJws;
}
/**
* 解析验证token
*
* @param token
* @return
* @throws Exception
*/
public static Jws<Claims> parserToken(String token) throws Exception {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(JWT_SECRET.getBytes()).parseClaimsJws(token);
return claimsJws;
}
/**
* 获取token中的用户信息
*
* @param token
* @return
* @throws Exception
*/
public static JWTInfo getInfoFromToken(String token) throws Exception {
Jws<Claims> claimsJws = parserToken(token);
Claims body = claimsJws.getBody();
return new JWTInfo(getObjectValue(body.get("userId")), getObjectValue(body.get("userName")));
}
private static String getObjectValue(Object obj){
return obj==null?"":obj.toString();
}
}
5. 创建拦截器
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 拦截器获取token并验证token
* @author: clx
* @date: 2019/7/22
* @version: 1.1.0
*/
public class JWTInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
// 如果不是映射到方法直接通过
if(!(object instanceof HandlerMethod)){
return true;
}
// 从 http 请求头中取出 token
String token = request.getHeader("Authorization");
System.out.println(request.getRequestURI());
if (StringUtils.isBlank(token)) {
throw new RuntimeException("无token,请重新登录");
}
// 校验token
JWTHelper.parserToken(token);
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
}
}
6. 注册拦截器
注意: 要把测试controller中的 获取token和不需要token就能调用的接口先过滤掉
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 拦截器注册
* @author: clx
* @date: 2019/5/27
* @version: 1.1.0
*/
@Configuration
public class JWTConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**")
// 过滤不来拦截的请求路径, 可以写在配置文件中读取
.excludePathPatterns("/jwtTest/unToken","/jwtTest/getToken");
}
@Bean
public JWTInterceptor authenticationInterceptor() {
return new JWTInterceptor();
}
}
7. 创建测试
import com.example.jwtdemo.jwt.JWTHelper;
import com.example.jwtdemo.jwt.JWTInfo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* jwt测试类
* @author: clx
* @date: 2019/7/22
* @version: 1.1.0
*/
@RestController
@RequestMapping("/jwtTest")
public class JWTTestController {
/**
* 获得token
* @param userId
* @param userName
* @return
* @throws Exception
*/
@GetMapping("/getToken")
public Object getToken(String userId, String userName) throws Exception {
return JWTHelper.generateToken(new JWTInfo(userId, userName), 0);
}
/**
* 不需要验证的接口
* @return
*/
@GetMapping("/unToken")
public String unToken() {
return "不需要验证token,接口调用成功";
}
/**
* 需要验证的接口
* @return
*/
@GetMapping("/needToken")
public String needToken() {
return "token验证正常,接口调用成功";
}
}
8. 启动项目测试
8.1 获取token
获取token成功
8.2 调用不需要token的接口
调用成功
8.2 调用需要token验证的接口
1)先不添加token调用
无法访问接口,提示错误信息
2) 带上8,1返回的token进行访问
调用成功,返回对应数据
9. 成功