需要工具:MySQL数据库(且默认已连接完成),idea,maven构建项目(其他的可以换方法下jar包)
pom文件:
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.2.1
com.example
TianyiDemo
0.0.1-SNAPSHOT
TianyiDemo
TianyiDemo
17
org.mybatis.spring.boot
mybatis-spring-boot-starter
3.0.3
com.mysql
mysql-connector-j
runtime
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
junit
junit
org.mybatis.spring.boot
mybatis-spring-boot-starter-test
3.0.3
org.springframework
spring-web
6.1.1
org.springframework
spring-webmvc
6.1.1
io.leopard.boot
leopard-boot-requestmapping
0.9.20
org.springframework.boot
spring-boot-starter-web
io.jsonwebtoken
jjwt
0.9.1
javax.xml.bind
jaxb-api
2.2.11
com.sun.xml.bind
jaxb-core
2.2.11
com.sun.xml.bind
jaxb-impl
2.2.11
javax.activation
activation
1.1.1
com.alibaba
fastjson
1.2.76
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok
Result统一响应实体类:
@Data
@NoArgsConstructor
@AllArgsConstructor
//设置浏览器响应统一返回结果
public class Result {
private Integer code;//响应码,1 代表成功; 0 代表失败
private String msg; //响应信息 描述字符串
private Object data; //返回的数据
//增删改 成功响应
public static Result success(){
return new Result(1,"success",null);
}
//查询 成功响应
public static Result success(Object data){
return new Result(1,"success",data);
}
//失败响应
public static Result error(String msg){
return new Result(0,msg,null);
}
}
添加jwt依赖和fastjson(进行格式转换):
io.jsonwebtoken
jjwt
0.9.1
com.alibaba
fastjson
1.2.76
注意:jdk8以上已经移除一个其中类:
报错请参考:springboot maven项目针对于jwt包导入后无法使用报错,前端测试响应为500
编写工具类JwtUtils
package com.example.tianyidemo.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtils {
private static String signKey = "ithtmljava";
private static Long expire = 43200000L;
/**
* 生成JWT令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @return
*/
public static String generateJwt(Map claims){
String jwt = Jwts.builder()
.addClaims(claims)
.signWith(SignatureAlgorithm.HS256, signKey)
.setExpiration(new Date(System.currentTimeMillis() + expire))
.compact();
return jwt;
}
/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载 payload 中存储的内容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
编写配置类webconfing(表明要拦截所有路径,除了login路径外)
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
}
}
(已默认编写登录接口)在登录接口中进行条件判断,是否利用jwt工具类生成并下发jwt令牌,Result为统一响应结果,可以不用,如果需要,请在参考中拿取为实体类。
@Slf4j
@CrossOrigin//准许跨域请求
@RestController//包含@Controller(三层架构声明控制器)和@ResponseBody(转化json格式)
public class LoginController {
@Autowired
private UserService userService;
@PostMapping("/login")
public Result login(@RequestBody User user){
log.info("登录:{}",user);
User u = userService.login(user);
// 登录成功,生成令牌,下发令牌
if (u != null){
Map claims = new HashMap<>();
claims.put("id",u.getUserID());
claims.put("name",u.getUserName());
String jwt = JwtUtils.generateJwt(claims);
return Result.success(jwt);
}
// 登录失败
return Result.error("错误!");
}
}
编写拦截器,在请求进入时进行拦截认证,查看token是否符合
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override//目标资源方法运行前运行,返回ture放行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取请求的url
String url = request.getRequestURI().toString();
log.info("请求的url:{}",url);
//判断请求的url中是否包含login,如果包含,说明是登录操作,放行
if (url.contains("login")){
log.info("登录操作,放行");
return true;
}
//获取请求头的的令牌token
String jwt = request.getHeader("token");
log.info(jwt);
//判断令牌是否存在,不存在返回错误就结果
if (!StringUtils.hasLength(jwt)){
log.info("请求头中的token信息为空,返回未登录的信息");
Result error = Result.error("NOT INdex");
String notLogin = JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return false;
}
//解析token失败,返回错误结果
try{
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
e.printStackTrace();
log.info("解析失败,返回错误信息");
Result error = Result.error("NOT INdexToken");
String notLogin = JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return false;
}
// 放行
log.info("令牌配对成功,放行!");
return true;
}
@Override//目标资源运行后运行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
@Override//视图渲染后完成,最后运行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion(完成后完成)...");
}
}
现阶段逻辑分析:
登录请求被接收-----发送到拦截器-----(配置类)拦截器中排除掉非login路径---------(登录控制器登录判断)确认登录成功且路径正确后开始生成token-----(拦截器类)对请求中的token进行验证
在其中添加输出语句或者断点进行调试后用apifex进行前端测试,成功获取token
(注意:请在前端测试请求中加入用户数据以便于通过登录判断!)