
通过jwt官网可以看到,jwt形成的编码是由声明、数据、密钥等部分组成,将登录的用户数据存储到map中,进行编码生成,
jwt生成和解析工具类
java
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 = "密钥自定义";
//过期时间
private static Long expire = 1000 * 3600 * 24 * 7L;
//生成jwt
public static String generateJwt(Map<String,Object> map){
return Jwts.builder().addClaims(map)//设置声明(有效数据)
.signWith(SignatureAlgorithm.HS256,signKey)//设置(使用的算法规则,密钥-自己定义的-不能少于四位)
.setExpiration(new Date(System.currentTimeMillis()+expire))//设置过期时间
.compact();//设置生效
}
//解析jwt Claims-map结构 可以使用get方法去取值,返回的是用户信息,表示是登录状态的
public static Claims parseJwt(String jwt){
return Jwts.parser()
.setSigningKey(signKey) //密钥
.parseClaimsJws(jwt) //调用jws 指定生成的令牌
.getBody();
}
}
登录业务实现
Controller
这里将业务处理放到了service中,controller简单进行了调用,通过前端传递的用户名和密码,将其封装在员工表Emp中
java
@RestController
public class LoginController {
@Autowired
private EmpService empService;
@PostMapping("/login")
public Result login(@RequestBody Emp emp){
return empService.login(emp);
}
}
service
java
//接口:
Result login(Emp emp);
//实现类:
@Override
public Result login(Emp emp) {
//通过mapper查询数据库中是否存在用户名和密码一致的用户
Emp em = empMapper.selByNameAndPass(emp);
//如果查询到,表示用户存在
if (em != null){
//通过新建map,将需要放到token里面的数据进行put
Map<String, Object> map = new HashMap<>();
map.put("id",em.getId());
map.put("username",em.getUsername());
//调用工具类,进行token生成
String token = JwtUtils.generateJwt(map);
//将生成的token返回给前端
return Result.success(token);
}else {
//没查询到,表示信息有误
throw new LoginException("用户名或密码错误");
}
}
mapper
java
//接口:
Emp selByNameAndPass(Emp emp);
//xml:
<select id="selByNameAndPass" resultType="cn.emp.domain.Emp">
select * from emp where username = #{username} and password = #{password}
</select>
拦截器
通过拦截器实现,没有登录信息token符合要求时,跳转到登录页进行登录
java
import cn.wolfcode.domain.Result;
import cn.wolfcode.util.JwtUtils;
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
try {
String token = request.getHeader("token");
JwtUtils.parseJwt(token);
return true;
} catch (Exception e) {
response.setContentType("application:json/charset=utf-8");
Result result = Result.error("NOT_LOGIN");
String jsonString = JSONObject.toJSONString(result);
response.getWriter().write(jsonString);
return false;
}
}
}
设置拦截的路径和放行的路径
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//将当前类转变为配置类
@Configuration
public class WebConfig implements WebMvcConfigurer {
//拿到定义的拦截器
@Autowired
private LoginInterceptor loginInterceptor;
//拦截器注册表
@Override
public void addInterceptors(InterceptorRegistry registry) {
/*
* 拦截器如果拦截的路径是 /* 只能拦截一级路径
* '/**' 可以拦截多级路径
* excludePathPatterns 设置放行路径
*/
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
}
过滤器
java
import cn.wolfcode.domain.Result;
import cn.wolfcode.util.JWTUtils;
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
//给过滤器配置要过滤的路径
@WebFilter("/*")
public class DemoFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//认证逻辑
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse)response;
//login接口放行,拿到请求资源URI
String requestURI = req.getRequestURI();
if (requestURI.contains("/login")){
chain.doFilter(request,response);
//结束后续方法执行
return;
}
//获取令牌
String token = req.getHeader("token");
try {
//进行解析 有异常不放行,没有异常放行
JWTUtils.parseJwt(token);
//负责放行的语句
chain.doFilter(request,response);
} catch (IOException e) {
//原生响应
resp.setContentType("application/json;charset=utf-8");
Result result = Result.error("NOT_LOGIN");
//将result对象手动转换为json(通过添加fastjson依赖实现)
String jsonString = JSONObject.toJSONString(result);
resp.getWriter().write(jsonString);
}
}
}
过滤器需要在启动类上添加注解,使过滤器生效
//使filter注解生效
@ServletComponentScan
过滤器和拦截器选择一个进行实现就可以