登录认证
没有真正意义上的完成
要想解决问题,需要做两件事情:
用户完成登入后,给用户一个登入成功的标记;
浏览器发出请求时,需要进行拦截,有登入成功标记,就放行,没有就返回登入页面。
会话跟踪技术
会话 : 打开浏览器 , 发起请求到服务端 , 会话建立 。 一次会话,可以包含多个请求响应 。
会话跟踪技术实现方法
1). 客户端会话跟踪技术:Cookie
2). 服务端会话跟踪技术:Session
这两个技术都可以实现会话跟踪,它们之间最大的区别:Cookie是存储在浏览器端,而Session是存储在服务器端
。
缺点:
①. 在集群环境下部署, 无法使用session (session无法在多个服务器共享)
②. 移动端APP无法使用Cookie.
JWT令牌
pom.xml 引入jwt的依赖
String jwt = Jwts.builder()
.setClaims(claims) //执行第二部分负载, 存储的数据
.signWith(SignatureAlgorithm.HS256, "itheima") //签名算法及秘钥
.setExpiration(new Date(System.currentTimeMillis() + 12*3600*1000)) //设置令牌的有效期
.compact();
校验
Jwts.parser()
.setSigningKey("密钥")
.parseClaimsJws("令牌")
.getBody();
统一拦截请求,
在服务端,我们可以通过两种手段实现:过滤器Filter、拦截器Interceptor。
过滤器Filter
概念:Filter 过滤器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一
过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
过滤器一般完成一些通用的操作,比如:登陆鉴权、统一编码处理、敏感字符处理等等…
定义:
1,定义类,实现 Filter接口,并重写doFilter
方法
2,配置Filter拦截资源的路径:在类上定义 @WebFilter 注解
3,在引导类上使用@ServletComponentScan
@WebFilter(urlpattern="/*")
public class LoginCheckFilter implments Filter {
doFilter : 每一次拦截请求都会调用
}
执行流程
放行后访问对应资源,资源访问完成后,还会回到Filter中吗? 答案:会
如果回到Filter中,是重新执行还是执行放行后的逻辑呢?答案:执行放行后逻辑
Filter 拦截路径
登入校验
A. 获取请求url, 判定是否是login登录请求, 如果是: 放行 ;
B. 获取请求头中token , 判定是否存在, 如果不存在, 返回错误信息 ;
C. 解析JWT令牌, 如果解析报错, 返回错误信息 ;
D. 放行 ;
拦截器Interceptor
拦截器:(Interceptor)是一种动态拦截方法调用的机制,类似于过滤器。在SpringMVC中动态拦截控制器方法的执行
作用:在指定的方法调用前后执行预先设定的代码,完成功能增强
定义
- 定义拦截器,实现HandlerInterceptor接口,并重写其所有方法。
- 注册拦截器
@Component
public class LoginCheckInterceptor implments HandlerInterceptor {
preHandle: 控制器方法执行之前运行;
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
}
}
执行流程
Filter 与 Interceptor 区别
接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。
拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。
全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* Exception异常分类
* - 运行时异常 : RuntimeException , 编译时无需处理 .
* - 编译时异常 : 非 RuntimeException , 编译时处理 .
*/
@ExceptionHandler(Exception.class)
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error("系统繁忙, 请稍后重试 ... ");
}
}