整合SpringBoot
搭建SpringBoot+mybatis+jwt环境
1.引入依赖,编写配置
<!-- 引入jwt-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<!-- 引入mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<!--引入lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<!-- 引入druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
<!-- 引入mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/jwt?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
mybatis.type-aliases-package=com.sovzn.jwttest.entity
mybatis.mapper-locations=classpath:com/sovzn/mapper/*.xml
logging.level.com.sovzn.jwttest.dao
2.开发数据库
CREATE TABLE `jwt`.`user`(
`id` INT(11) NOT NULL COMMENT '主键',
`name` VARCHAR(88) NOT NULL COMMENT '用户名',
`password` VARCHAR(40) NOT NULL COMMENT '用户密码',
PRIMARY KEY (`id`)
) ENGINE=INNODB CHARSET=utf8 COLLATE=utf8_general_ci;
INSERT INTO `jwt`.`user` (`id`, `name`, `password`) VALUES ('1', 'sovzn', '123');
3.开发entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String id;
private String name;
private String password;
}
4.开发Dao接口和mapper.xml
@Mapper
public interface UserDao {
User login(User user);
}
<mapper namespace="com.sovzn.jwttest.dao.UserDao">
<!--一个简单的查询-->
<select id="login" parameterType="User" resultType="User">
select * from user where name=#{name} and password=#{password}
</select>
</mapper>
5.开发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("认证失败");
}
}
6.开发controller
@RestController
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/user/login")
public Map<String,Object> login( User user){
log.info("用户名:[{}]",user.getName());
log.info("密码:[{}]",user.getPassword());
Map<String,Object> map=new HashMap<>();
try {
User userDB=userService.login(user);
// 生成JWT令牌 使用封装的工具类
Map<String,String> payload =new HashMap<>();
payload.put("id",userDB.getId());
payload.put("name",userDB.getName());
String token= JWTutils.getToken(payload);
map.put("status",true);
map.put("msg","认证成功");
map.put("token",token);
} catch (Exception e) {
map.put("status",false);
map.put("msg",e.getMessage());
}
return map;
}
@GetMapping("/user/test") //测试接口 携带token访问接口
public Map<String,Object> test(String token){
Map<String,Object> map=new HashMap<>();
log.info("当前token:[{}]",token);
try {
DecodedJWT verify= JWTutils.getTokenInfo(token); //验证令牌
map.put("status",true);
map.put("msg","请求成功");
/*
完成要执行的业务逻辑
*/
return map;
}
catch (SignatureVerificationException e) {
e.printStackTrace();
map.put("msg","签名无效");
}
catch (TokenExpiredException e){
e.printStackTrace();
map.put("msg","令牌过期");
}
catch (AlgorithmMismatchException e){
e.printStackTrace();
map.put("msg","算法不匹配");
}
catch (Exception e){
e.printStackTrace();
map.put("msg","token无效");
}
map.put("status",false);
return map;
}
}
7.在浏览器中模拟登陆
输入URL
http://localhost:8080/user/login?name=sovzn&password=123
执行结果返回:
{
"msg": "认证成功",
"status": true,
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoic292em4iLCJpZCI6IjEiLCJleHAiOjE2MTE0NzgxNDR9.26W7rhPqA5C8wOJ1GH6U40bRJh3l40LMXopth6PsXf4"
}
8.模拟携带token访问接口
输入URL携带登陆后得到的token
http://localhost:8080/user/test?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoic292em4iLCJpZCI6IjEiLCJleHAiOjE2MTE0NzkyMTN9.yoBPr-LZGwdHmdnQ_optlspKSpoxE6dDsCQUUD17MAs
执行结果返回:
{
"msg": "请求成功",
"status": true
}
问题?
使用上述方式每次都要传递token数据,每个接口方法都需要验证token,这样显得代码冗余。
优化:
对于web项目可以使用拦截器来优化
对于分布式可以使用网关来优化
1.编写拦截器:
//实现springmvc提供的拦截器接口
public class JWTinterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//官方推荐把jwt 放在请求头里
//获取请求头里的令牌
String token = request.getHeader("token");
Map<String,Object> map=new HashMap<>();
try {
JWTutils.getTokenInfo(token); //验证令牌
return true;//放行
}
catch (SignatureVerificationException e) {
e.printStackTrace();
map.put("msg","签名无效");
}
catch (TokenExpiredException e){
e.printStackTrace();
map.put("msg","令牌过期");
}
catch (AlgorithmMismatchException e){
e.printStackTrace();
map.put("msg","算法不匹配");
}
catch (Exception e){
e.printStackTrace();
map.put("msg","token无效");
}
map.put("status",false);
//将map转为json 相应给前台
String json = new ObjectMapper().writeValueAsString(map);
response.setContentType("application/json;charset=utf-8");
response.getWriter().println(json);
return false;
}
}
2.配置拦截器
//配置类 实现WebMvcConfigurer
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTinterceptor())//添加拦截器
.addPathPatterns("/**") //添加拦截的路径
.excludePathPatterns("/user/login"); //添加放行的路径
}
}
3.修改测试接口
@PostMapping("/user/test") //测试接口
public Map<String,Object> test(HttpServletRequest request){
Map<String,Object> map=new HashMap<>();
String token=request.getHeader("token");
DecodedJWT verify=JWTutils.getTokenInfo(token);
map.put("用户id",verify.getClaim("id").asString());//然后可以根据得到的用户id进行业务处理
map.put("status",true);
map.put("msg","有权访问该接口");
return map;
}
测试:
1.浏览器输入URL得到token
http://localhost:8080/user/login?name=sovzn&password=123
结果:
{
"msg": "认证成功",
"status": true,
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoic292em4iLCJpZCI6IjEiLCJleHAiOjE2MTE0ODU1Nzh9.NLz6CYM415FrQid7VKCz5y73bDSAtOyrVD8ZW_xDv3c"
}
2.输入URLhttp://localhost:8080/user/test 并将token设置在请求头中
{
"msg": "有权访问该接口",
"用户id": "1",
"status": true
}
给个饭钱?
- Post link: http://sovzn.github.io/2021/01/17/JWT-SpringBoot/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub Issues