登陆页面
1 判断账号密码是否一致
1.1 添加jjwt依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
1.2 编写JWTUtils工具类
public class JWTUtils {
//匿名构造器
private JWTUtils(){}
public static String createJWTStr(Map<String,Object> map) {
//利用JJWT api的builder方法生成令牌
String jwtStr = Jwts.builder()
//签名编码和签名,签名不能有中文, 否则超出界定范围
.signWith(SignatureAlgorithm.HS256, "Donald Trump")
//payload--有效载荷--自定义传参
.addClaims(map)
//设置有效期限. 1000*60*10 = 1000毫秒(1秒)*60(分钟/秒)*10 == 10分钟
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 10 ))
// 编写 => 输出格式为String
.compact();
System.out.println(jwtStr);
return jwtStr;
}
//解析JWT令牌
public static void parseJWTStr(String str){
Jwts.parser()
// 签名
.setSigningKey("Donald Trump")
// 解析(令牌)
.parse(str)
//获得body
.getBody();
}
}
1.3 编写 Controller
@RestController
@Slf4j
public class LoginController {
@Autowired
private LoginService loginService;
@PostMapping("/login")
public Result login(@RequestBody Emp emp) {
Emp empReturn = loginService.login(emp);
//返回值null代表登录失败
if(empReturn == null){
return Result.failed();
}else {
//登陆成功, 制造JWT令牌
Map map = new HashMap<>();
map.put("username",emp.getUsername());
map.put("id",emp.getId());
//用JWTUtils工具类生成JWT令牌
String jwtStr = JWTUtils.createJWTStr(map);
return Result.success(jwtStr);
}
}
}
1.4 编写Service (可以看成是用户的Service)
@Service
public class LoginServiceImpl implements LoginService {
@Autowired
private LoginMapper loginmapper;
@Override
public Emp login(Emp emp) {
//mapp查找,成功返回Emp对象, 失败则不返回对象
Emp empReturn = loginmapper.login(emp);
return empReturn;
}
}
1.5 编写Mapper (可以看成是用户的Mapper)
@Mapper
public interface LoginMapper {
@Select("select * from emp where username = #{username} and password = #{password}")
Emp login(Emp emp);
}
1.6 异常和报错
1.6.1 制作登陆token令牌时报错
在制作登陆令牌时偶尔会出现 ERROR: .ClassNotFoundException 错误, 这是因为在 Java 9 及以上的版本中,javax.xml.bind.DatatypeConverter
类被标记为不推荐使用,并且从标准的 Java SE 库中移除。因此,在某些情况下,当代码依赖旧的库或框架时,可能会出现该异常。
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter] with root cause
解决办法是手动添加jaxb-api依赖
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
1.6.2 解析token令牌时报错
解析过程中发现parseJWT() 报错ERROR:
.IllegalArgumentException: A signing key must be specified if the specified JWT is digitally signed
原因是生成token和解析token所设置的Signingkey不匹配导致.
解决办法就是检查两次设置的signingkey是否匹配
2 Filter 过滤器
2.1 编写一个类实现Filter接口并重写其所有方法, 并在Filter类上加 @WebFilter 注解,配置拦截资源的路径
# 添加依赖fastjson
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
//@WebFilter(urlPatterns ="/*")的作用是对所有 URL 请求进行拦截和处理。
@WebFilter(urlPatterns ="/*")
public class doFilter implements Filter {
//初始化方法, 只调用一次
@Override
// FilterConfig 对象可以获取到 ServletContext 和其他配置参数
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init 初始化方法执行了");
}
// ctrl+o 重写方法
//拦截到请求之后调用, 调用多次
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Demo 拦截到了请求...放行前逻辑");
//强制转换以便于获取请求
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 获取请求url URI 是一个用于标识资源的字符串
String url = request.getRequestURI();
System.out.println("拦截了:"+url);
// 判断请求url是否包含login, 有则放行
if(url.contains("login")){
//filter的放行方法
filterChain.doFilter(servletRequest,servletResponse);
return;
}
// 获取请求头中token
String token = request.getHeader("token");
// 利用StringUtils工具类的方法判断token是否存在
if(!StringUtils.hasLength(token)){
Result r = Result.failed("NOT_LOGIN");
//序列化为 JSON 格式的字符串
String jsonStr = JSONObject.toJSONString(r);
//写入响应中
response.getWriter().write(jsonStr);
return;
}
//解析token
try{
JWTUtils.parseJWTStr(token);
// 解析成功,则放行
filterChain.doFilter(servletRequest,servletResponse);
}catch (Exception e){
e.printStackTrace();
Result r = Result.failed("NOT_LOGIN");
String jsonStr = JSONObject.toJSONString(r);
response.getWriter().write(jsonStr);
return;
}
System.out.println("过滤执行了");
}
//销毁方法, 只调用一次
@Override
public void destroy() {
System.out.println("destroy 销毁方法执行了");
}
}
2.2 在引导类上加 @ServletComponentScan 开启Servlet组件
@ServletComponentScan
@SpringBootApplication
public class Day25TillasRe3Application {
public static void main(String[] args) {
SpringApplication.run(Day25TillasRe3Application.class, args);
}
}
3 Interceptor 拦截器
3.1 定义拦截器,实现HandlerInterceptor接口,并重写其所有方法。
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截呀");
String url = request.getRequestURI();
System.out.println("拦截了"+ url);
//判断请求rul中是否包含login
if(url.contains("login")){
return true;
}
//获取请求token
String token = request.getHeader("token");
//判断令牌是否存在
if(!StringUtils.hasLength(token)){
Result r = Result.failed("NOT_LOGIN");
//拼接json
String string = JSONObject.toJSONString(r);
response.getWriter().write(string);
return false;
}
//解析
try{
JWTUtils.parseJWTStr(token);
return true;
}catch (Exception e){
e.printStackTrace();
Result r = Result.failed("NOT_LOGIN");
//拼接json
String string = JSONObject.toJSONString(r);
response.getWriter().write(string);
return false;
}
}
@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");
}
}
3.2 生成一个Config文件夹 内有 Cofig配置文件, 在配置文件中注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
//addInterceptors方法用于添加拦截器到拦截器注册表(InterceptorRegistry)
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
}
}
4 Global Exception Handler 全局异常处理器
//@RestControllerAdvice捕获应用程序中抛出的所有类型的 Exception 异常,并进行统一处理。
//@RestControllerAdvice = @ResponseBody +@Controller Advice
@RestControllerAdvice
public class GlobalExceptionHandler {
// @ExceptionHandler 注解标识的参数指定了要处理的异常类型为 Exception.class,
// 表示捕获所有的异常。当应用程序中抛出异常时,会被这个方法捕获到
@ExceptionHandler(Exception.class)
public Result exception(Exception ex){
// 打印堆栈信息
ex.printStackTrace();
return Result.failed("you are failed");
}
}