登录(六)


登录(六)

会话技术

会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束,在一次会话中可以包含多次请求和响应。

会话跟踪:一种维护浏览器状态的方法,服务器需识别多次请求是否来自同一浏览器,以便在同一次会话的多次请求见共享数据。

会话跟踪方案

  • 客户端会话跟踪技术:Cookie
  • 服务端会话跟踪技术:Session
  • 令牌技术

优点:http协议中支持的技术。

缺点

  • 移动端APP无法使用Cookie
  • 不安全,用户可以自己禁用Cookie
  • Cookie不能跨域

Session

优点:存储在服务器,安全。

缺点

  • 服务器集群环境下无法直接使用Session
  • Cookie的缺点

令牌技术

优点

  • 支持PC,移动端
  • 解决集群环境下的认证问题
  • 减轻服务器端存储压力

缺点:需自己实现

JWT

JWT全程JSON Web Token。

定义一组简洁的,自包含的格式,用于在通信双方以JSON数据格式安全的传递信息。由于数据签名的存在,这些信息是可靠的。

组成

  1. Header(头),记录令牌类型,签名算法。
  2. Payload(有效荷载):携带一些自定义信息,默认信息等。
  3. Signature(签名),防止Token被篡改,确保安全性,将header,payload,并加入指定秘钥,通过指定签名算法计算而来。

使用场景:登录认证

登录认证

  1. 登录成功后,生成令牌。
  2. 后续每个请求,都要携带JWT令牌,系统在每次请求处理之前,先校验令牌,通过后,再处理

依赖

1
2
3
4
5
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>

生成和校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 //生成
@Test
void jwtGenerate(){
Map<String,Object> map=new HashMap<>();
map.put("a",1);
map.put("b",2);
String ljsblog = Jwts.builder()
.setClaims(map)
.signWith(SignatureAlgorithm.HS256, "ljsblog")
.setExpiration(new Date(System.currentTimeMillis()+1000*3600*12))//一天后失效
.compact();
System.out.println(ljsblog);
}

//校验
@Test
void jwtCertify(){
Claims ljsblog = Jwts.parser()
.setSigningKey("ljsblog")
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJhIjoxLCJiIjoyLCJleHAiOjE2ODQzNTc4NzV9.jr-x-QlFpVgt44kc-8Mfyduzd_m10jb7pwhyxPtYfwQ")
.getBody();
System.out.println(ljsblog);
}

  1. JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥配套
  2. 若JWT令牌解析校验时报错,则说明JWT令牌被纂改或失效,令牌非法

Filter过滤器

Filter过滤器:是Javaweb三大组件(Servlet,Filter,Listener)之一。

过滤器可把资源的请求拦截下来,从而实现一些特殊功能。

过滤器一般完成一些通用操作,比如:登录校验,统一编码处理,敏感字符处理等。

Filter快速入门

  1. 定义Filter
    • 定义一个类,实现Filter接口,并重写其所有方法
  2. 配置Filter
    • Filter类加@WebFilter注解,配置拦截资源的路径,引导类加上@ServletComponentScan开启Servlet组建支持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.ljsblog.file;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

}

@Override
public void destroy() {
Filter.super.destroy();
}
}

package com.ljsblog;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
public class TliasWebManagmentApplication {

public static void main(String[] args) {
SpringApplication.run(TliasWebManagmentApplication.class, args);
}

}

Filter拦截路径

  • 拦截具体路径
    • urlPatterns值:/路径名
    • 只有访问/路径名时,才会被拦截
  • 目录拦截
    • urlPatterns值:/路径名/*
    • 访问/路径名下的所有资源,都会被拦截
  • 拦截所有
    • urlPatterns值:/*
    • 访问所有资源,都会被拦截

执行流程

  1. 请求
  2. 放行前逻辑
  3. 放行
  4. 资源
  5. 放行后逻辑

过滤器链

一个web应用中,配置多个过滤器,就形成一个过滤器链

顺序:注解配置的Filter,优先级是按照过滤器类名(字符串)的自然排序

登录校验filter

  1. 除了登录请求,其余请求拦截到都需要校验令牌
  2. 拦截到请求后,有令牌且令牌校验通过(合法)才可以放行,否则都会返回登录错误结果

流程

  1. 获取请求url
  2. 判断请求url中是否包含login,若包含,说明是登录操作,放行。
  3. 获取请求头中的令牌(token)
  4. 判断令牌时否存在,若不存在,返回错误结果(未登录)
  5. 解析token,若解析失败,返回错误结果(未登录)
  6. 放行

拦截器

拦截器是一种动态拦截方法调用的机制,类似于过滤器,Spring框架中提供的,用来动态拦截控制器方法的执行,可用来拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。

Interceptor快速入门

  1. 定义拦截器,实现HandlerInterceptor接口,并重写其所有方法
  2. 注册拦截器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Component
public class CheckInterceptor implements HandlerInterceptor {

@Override//目标资源方法执行前执行,返回true,放行;返回false,不放行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
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");
}
}



@Configuration
public class WebConfig implements WebMvcConfigurer{
@Autowired
private CheckInterceptor checkInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(checkInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
}
}

拦截路径

addPathPatterns:需要拦截的资源。

excludePathPatterns:不需要拦截的资源。

  • 拦截路径:/*
    • 一级路径
  • 拦截路径:/**
    • 任意级路径
  • 拦截路径:/路径名/*
    • /路径名 下的一级路径
  • 拦截路径:/路径名/**
    • /路径名 下的任意级路径

Filter和Interceptor的区别

  • 接口规范不同
    • 过滤器需要实现Filter接口
    • 拦截器需要实现HandlerInterceptor接口
  • 拦截范围不同
    • 过滤器会拦截所有资源
    • 拦截器只拦截Spring环境中的资源

全局异常处理器

1
2
3
4
5
6
7
8
9
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error("操作失败,请联系管理员");
}
}


Author: ljs
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source ljs !
评论
  TOC