Java 登录专题

核心背景:HTTP 是无状态的

服务器默认不记得你是谁

  • 请求1 ------ 完了就忘
  • 请求2 ------ 当新请求

在客户端保存状态标识,解决 HTTP 无状态问题

java 复制代码
@GetMapping("/hello")
public String hello(HttpServletResponse response) {
    Cookie cookie = new Cookie("name", "value");
    // 20秒后过期
    cookie.setMaxAge(20);
    response.addCookie(cookie);
    return "OK";
}

@GetMapping("/user")
public void user(HttpServletRequest request) {
    Cookie[] cookies = request.getCookies();
    for (Cookie cookie : cookies) {
        if (cookie.getName().equals("name")) {
            System.out.println(cookie.getName() + ":" + cookie.getValue());
        }
    }
}

后端设置 cookie 时

前端发起请求携带 cookie 时

cookie 管理界面

优缺点

优点:HTTP协议中支持的技术

缺点:

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

Session

HttpSession 是服务器端保存用户会话状态的对象

核心特点:

  • 存在服务器内存(或 Redis)
  • 以 SessionId 为索引
  • 解决 HTTP 无状态问题

Session 是怎么连续的?(核心原理)

第一次访问之后,会产生一个Cookie,往后访问都会带着它

java 复制代码
// 存值
@GetMapping("/hello")
public String hello(HttpSession session) {
    log.info("HttpSession-s1:{}", session.hashCode());
    session.setAttribute("name", "hello");
    return "OK";
}

    // 获取值
@GetMapping("/user")
public void user(HttpSession session) {
    log.info("HttpSession-s2:{}", session.hashCode());
    Object name = session.getAttribute("name");
    log.info("name: {}", name);
}

缺点,分布式集群下无法使用 Session

优点:数据存放到服务端

令牌JWT

令牌会话跟踪方案的优缺点 ?

优点:

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

缺点:需要自己实现

全称:JSON Web Token (jwt.io/)

定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。 组成:

  • 第一部分:Header(头),记录令牌类型、签名算法等。 例如:{"alg":"HS256","type":"JWT"}
  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{"id":"1","username":"Tom"}
  • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload融入,并加入指定密钥,通过指定签名算法计算而来。

Base64:是一种基于64个可打印字符(A-Z a-z 0-9 + /)来表示二进制数据的编码方式。

引入 maven

xml 复制代码
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.12.6</version>
</dependency>
java 复制代码
HashMap<String, Object> map = new HashMap<>();
map.put("id", 1);
map.put("name", "admin");

// 字符串中应该,base64机密的,加密内容必须足够长
String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256,
                "abcdefghijklmn")
        // 自定义数据
        .addClaims(map)
        // 过期时间, 单位毫秒 + 1小时
        .setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))
        .compact();

return jwt;

打印 JWT,用三个 . 分出来三个部分

eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYWRtaW4iLCJpZCI6MSwiZXhwIjoxNzY2MjI3Njk5fQ.ZBiknENQ1NoKxv4myhVF2uS-toijk90uXz9O70Mhg9s

  1. 第一个部分,base64 解密是:{"alg":"HS256"}
  2. 第二部分,就是我们存入的对象
  3. 第三部分,就是加密字符串

令牌生成

java 复制代码
HashMap<String, Object> map = new HashMap<>();
    map.put("id", 1);
    map.put("name", "admin");

    // 字符串中应该,base64加密的,加密内容必须足够长
    String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256,
                    "abcdefghijklmn")
            // 自定义数据
            .addClaims(map)
            // 过期时间, 单位毫秒 + 1小时
            .setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))
            .compact();

令牌解析

java 复制代码
String token = "eyJhbGciOiJIUzI1NiJ9...";
// claims 实际就是 map
Claims claims = Jwts.parser().setSigningKey("abcdefghijklmn")
        .parseClaimsJws(token).getBody();

过滤器

多个过滤器是按照姓名

java 复制代码
// 开启SpringBoot 对 Servlet 组件的扫描
@ServletComponentScan
@SpringBootApplication
public class DemoApplication {

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

}

配置过滤器

java 复制代码
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {

    // Web 服务器启动时调用
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    // 拦截请求
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        // 放行,不写就会被拦截
        chain.doFilter(request, response);

    }

    // Web 服务器关闭时调用
    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

拦截器

配置

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new DemoInterceptor())
                // 拦截所有请求
                .addPathPatterns("/**")
                // 不拦截的请求
                .excludePathPatterns("/login");
    }
}

拦截器

java 复制代码
public class DemoInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("在请求之前到,true 返回,false 返回");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("目标运行之后运行");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("请求彻底结束");
    }
}
相关推荐
2501_921649492 小时前
股票 API 对接, 接入德国法兰克福交易所(FWB/Xetra)实现量化分析
后端·python·websocket·金融·区块链
毕设源码-邱学长2 小时前
【开题答辩全过程】以 高校跨校选课系统为例,包含答辩的问题和答案
java·eclipse
shark_chili2 小时前
深入剖析arthas技术原理
后端
@淡 定2 小时前
缓存原理详解
java·spring·缓存
北城以北88882 小时前
RabbitMQ基础知识
spring boot·分布式·rabbitmq·intellij-idea
带刺的坐椅2 小时前
超越 SpringBoot 4.0了吗?OpenSolon v3.8, v3.7.4, v3.6.7 发布
java·ai·springboot·web·solon·flow·mcp
就叫飞六吧2 小时前
基于spring web实现简单分片上传demo
java·前端·spring
invicinble2 小时前
网站设计整体思路
spring boot
apihz2 小时前
免费手机号归属地查询API接口详细教程
android·java·运维·服务器·开发语言