一.封装工具类
public class JWTUtils {
/**
* 盐值
*/
private static final String SING="huang@1024955508";
/**
* 生成令牌
* @param map payload载荷声明参数
* @return
*/
public static String getToken(Map<String,String> map){
//获取日历对象
Calendar calendar=Calendar.getInstance();
//默认7天过期
calendar.add(Calendar.DATE, 7);
//新建一个JWT的Builder对象
JWTCreator.Builder builder = JWT.create();
//将map集合中的数据设置进payload
map.forEach((k,v)->{
builder.withClaim(k, v);
});
//设置过期时间和签名
String sign = builder
.withExpiresAt(calendar.getTime())
.sign(Algorithm.HMAC256(SING));
return sign;
}
/**
* 验签并返回DecodedJWT
* @param token 令牌
*/
public static DecodedJWT verify(String token){
return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
}
}
二.整合springboot
搭建springboot+mybatis+jwt环境
- 引入依赖
- 编写配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--JWT的依赖-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<!--引入mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!--引入lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<!--引入druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
<!--引入mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
server.port=8080
spring.application.name=jwt
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/jwt?serverTimezone=UTC&useUnicode=false&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
mybatis.type-aliases-package=com.huang.pojo
mybatis.mapper-locations=classpath:mapper/*.xml
logging.level.com.huang.dao=debug
1.数据库
这里采用最简单的表结构验证JWT使用
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(80) DEFAULT NULL COMMENT '用户名',
`password` varchar(40) DEFAULT NULL COMMENT '用户密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
2.pojo
@Data
@Accessors(chain=true)
public class User {
private String id;
private String name;
private String password;
}
3.开发DAO接口和mapper.xml
@Mapper
public interface UserDAO {
User login(User user);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huang.dao.UserDao">
<select id="login" parameterType="User" resultType="User">
select * from jwt.user where name=#{name} and password = #{password}
</select>
</mapper>
4.开发Service 接口以及实现类
public interface UserService {
User login(User user);//登录接口
}
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
@Transactional(propagation = Propagation.SUPPORTS)
public User login(User user) {
User userDB = userDAO.login(user);
if(userDB!=null){
return userDB;
}
throw new RuntimeException("登录失败~~");
}
}
5.开发controller
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/user/login")
public Map<String,Object> login(User user){
System.out.println(user.getName());
System.out.println(user.getPassword());
Map<String,Object> map=new HashMap<>();
try {
User userDB = userService.login(user);
HashMap<String, String> payload = new HashMap<>(); //存放payload
payload.put("name",userDB.getName());
payload.put("password",userDB.getPassword());
map.put("state",true);
map.put("msg","用户密码正确成功");
//认证成功,生成token令牌
map.put("token",JWTUtils.getToken(payload));
} catch (Exception e) {
map.put("state",false);
map.put("msg",e.getMessage());
}
return map;
}
@GetMapping("/user/test")
public Map<String,Object> test(){
HashMap<String, Object> map = new HashMap<>();
map.put("msg","令牌验证成功");
return map;
}
}
6.编写JWT拦截器
- 使用上述方式每次都要传递token数据,每个方法都需要验证token代码冗余,不够灵活? 如何优化
- 使用拦截器进行优化
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取请求头中的令牌
String token = request.getHeader("token");
HashMap<String, Object> map = new HashMap<>();
try {
JWTUtils.verify(token);
return true;
} catch (TokenExpiredException e) {
map.put("msg", "Token已经过期!!!");
} catch (SignatureVerificationException e){
map.put("msg", "签名错误!!!");
} catch (AlgorithmMismatchException e){
map.put("msg", "加密算法不匹配!!!");
} catch (Exception e) {
e.printStackTrace();
map.put("msg", "无效token~~");
}
map.put("state",false); //设置状态
//将map转为json
String json = new ObjectMapper().writeValueAsString(map);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
return false;
}
}
7.编写拦截器配置类
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JwtInterceptor()) //添加拦截器
// .addPathPatterns("/**") //拦截路径
// .excludePathPatterns("/user/**"); //不拦截路径
.addPathPatterns("/user/test") //拦截路径
.excludePathPatterns("/user/login"); //不拦截路径
}
}