登入逻辑校验流程及JWT,拦截器,过滤器的相关知识
一 登入逻辑校验流程
1,参数校验
判断前端请求携带的用户名和密码是否为空
如果是为空程序就不用往下执行了
if (StrUtil.isBlank(loginDTO.getUsername())||StrUtil.isBlank(loginDTO.getPassword())){
throw new CustomException("用户名和密码不能为空");
}
2,逻辑处理
2.1 根据用户名查找到员工账户
Emp emp=loginMapper.findUsername(loginDTO.getUsername());
2.2对账户进行数据校验如果账户为空则表示没用这个账户
if (ObjUtil.isNull(emp)){
throw new CustomException("用户不存在");
}
2.3对账户进行密码校验如果不一致则用户输入的密码错误
if (!StrUtil.equals(emp.getPassword(),loginDTO.getPassword())){
throw new CustomException("用户名或密码错误");
}
3,通过校验的数据封装
3.1生成Jwt令牌
HashMap<String, Object> claims = new HashMap<>();
claims.put("id",emp.getId());
String token = JwtUtils.generateJwt(claims);
3.2并且将前端需要的数据连同token一起响应给前端
return LoginVO.builder().id(emp.getId())
.name(emp.getName())
.username(emp.getUsername())
.password(emp.getPassword())
.token(token)
.build();
二 Jwt,过滤器,拦截器的相关知识。
2.1JWT令牌
JWT令牌就是用户省份的标识,本质是一个字符串。
2.2 JWT全称 JSON Web Token 特点:
-
自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。
-
简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。
jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。
2.3 JWT的组成: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)
- 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:
- 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:
- 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。
2.4 JWT是如何将原始的JSON格式数据,转变为字符串的
- 其实在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码
- Base64:是一种基于64个可打印的字符来表示二进制数据的编码方式。既然能编码,那也就意味着也能解码。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。任何数据经过base64编码之后,最终就会通过这64个字符来表示。当然还有一个符号,那就是等号。等号它是一个补位的符号
- 需要注意的是Base64是编码方式,而不是加密方式。
2.5 生成和校验
2.5.1首先我们先来实现JWT令牌的生成。要想使用JWT令牌,需要先引入JWT的依赖:
<!-- JWT依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2.5.2生成JWT代码实现:
Map<String, Object> claims = new HashMap<>();
claims.put("id", 10);
claims.put("username", "itheima");
String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, "aXRjYXN0")
.addClaims(claims)
.setExpiration(new Date(System.currentTimeMillis() + 12 * 3600 * 1000))
.compact();
System.out.println(jwt);
eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjcyNzI5NzMwfQ.fHi0Ub8npbyt71UqLXDdLyipptLgxBUg_mSuGJtXtBk//加密后的jwt
2.5.2 实现了JWT令牌的生成,下面我们接着使用Java代码来校验JWT令牌(解析生成的令牌):
Claims claims = Jwts.parser().setSigningKey("aXRjYXN0")
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTAsInVzZXJuYW1lIjoiaXRoZWltYSIsImV4cCI6MTcwMTkwOTAxNX0.N-MD6DmoeIIY5lB5z73UFLN9u7veppx1K5_N_jS9Yko")
.getBody();
System.out.println(claims);
解密后
{id=10, username=itheima, exp=1701909015}
三 过滤器Filter
3.1过滤器的特点
- Filter表示过滤器,是 JavaWeb三大组件(Servlet、Filter、Listener)之一。
- 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能
- 使用了过滤器之后,要想访问web服务器上的资源,必须先经过滤器,过滤器处理完毕之后,才可以访问对应的资源。
- 过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。
3.2filter的使用入门
-
第1步,定义过滤器 :1.定义一个类,实现 Filter 接口,并重写其所有方法。
public class DemoFilter implements Filter { //初始化方法, web服务器启动, 创建Filter实例时调用, 只调用一次 public void init(FilterConfig filterConfig) throws ServletException { System.out.println("init ..."); } //拦截到请求时,调用该方法,可以调用多次 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { System.out.println("拦截到了请求..."); } //销毁方法, web服务器关闭时调用, 只调用一次 public void destroy() { System.out.println("destroy ... "); } }
-
第2步,配置过滤器:Filter类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet组件支持。
@WebFilter(urlPatterns = "/*") //配置过滤器要拦截的请求路径( /* 表示拦截浏览器的所有请求 ) public class DemoFilter implements Filter { //初始化方法, web服务器启动, 创建Filter实例时调用, 只调用一次 public void init(FilterConfig filterConfig) throws ServletException { System.out.println("init ..."); } //拦截到请求时,调用该方法,可以调用多次 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { System.out.println("拦截到了请求..."); } //销毁方法, web服务器关闭时调用, 只调用一次 public void destroy() { System.out.println("destroy ... "); } }
当我们在Filter类上面加了@WebFilter注解之后,接下来我们还需要在启动类上面加上一个注解
@ServletComponentScan
,通过这个@ServletComponentScan
注解来开启SpringBoot项目对于Servlet组件的支持。@SpringBootApplication public class TliasManagementApplication { public static void main(String[] args) { SpringApplication.run(TliasManagementApplication.class, args); } }
四 拦截器Interceptor
4.1定义
- 是一种动态拦截方法调用的机制,类似于过滤器。
- 拦截器是Spring框架中提供的,用来动态拦截控制器方法的执行。
- 拦截器的作用:拦截请求,在指定方法调用前后,根据业务需要执行预先设定的代码。
4.2基本使用
4.2.1定义拦截器
实现HandlerInterceptor接口,并重写其所有方法
//自定义拦截器
@Component
public class DemoInterceptor implements HandlerInterceptor {
//目标资源方法执行前执行。 返回true:放行 返回false:不放行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle .... ");
return true; //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 .... ");
}
}
4.2.2 注册配置拦截器
在 com.itheima
下创建一个包,然后创建一个配置类 WebConfig
, 实现 WebMvcConfigurer
接口,并重写 addInterceptors
方法
@Configuration
public class WebConfig implements WebMvcConfigurer {
//自定义的拦截器对象
@Autowired
private DemoInterceptor demoInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册自定义拦截器对象
registry.addInterceptor(demoInterceptor).addPathPatterns("/**");//设置拦截器拦截的请求路径( /** 表示拦截所有请求)
}
}
4.3常见拦截路径设置
拦截路径 | 含义 | 举例 |
---|---|---|
/* | 一级路径 | 能匹配/depts,/emps,/login,不能匹配 /depts/1 |
/** | 任意级路径 | 能匹配/depts,/depts/1,/depts/1/2 |
/depts/* | /depts下的一级路径 | 能匹配/depts/1,不能匹配/depts/1/2,/depts |
/depts/** | /depts下的任意级路径 | 能匹配/depts,/depts/1,/depts/1/2,不能匹配/emps/1 |