cookie、session、JWT

文章介绍了Web应用中常见的三种用户认证机制:Cookie用于在客户端存储信息,Session在服务器端存储用户信息,JWT则提供了一种更安全的跨域认证方式。每种机制有其优缺点,Cookie和Session易被窃取,JWT安全性更高但需管理Token的有效性。
摘要由CSDN通过智能技术生成

1、Cookie

Cookie 是一种存储在客户端浏览器中的小型文本文件,它包含了一些关于用户的信息,如用户名、密码等。当用户访问某个网站时,网站会将 Cookie 写入到用户的浏览器中,以便下次访问时可以自动登录。Cookie 的原理是,当用户访问网站时,浏览器会将 Cookie 发送给服务器,服务器根据 Cookie 中的信息来识别用户身份,从而实现免登录。

优点

  • 简单易用,浏览器自动处理Cookie的发送和接收。
  • 可以存储大量的信息,因为Cookie可以存储在客户端的浏览器中。
  • 可以设置过期时间,可以长期存储用户信息,不需要重复登录。

缺点

  • 安全性差,Cookie信息存储在客户端,容易被窃取和篡改。
  • 可能会被禁用或清除,导致用户需要重新登录。
  • Cookie只能存储文本信息,不适合存储二进制数据。

2、Session

Session 是一种在服务器端存储用户信息的技术。当用户登录时,服务器会为该用户创建一个 Session,将用户信息存储在 Session 中。当用户访问网站时,服务器会根据 Session 中的信息来识别用户身份,从而实现免登录。

当用户第一次访问网站时,服务器会为该用户创建一个 Session,并生成一个唯一的 Session ID,将 Session ID 存储在 Cookie 中,然后将用户信息存储在 Session 中。

当用户再次访问网站时,浏览器会将 Cookie 中的 Session ID 发送给服务器,服务器根据 Session ID 来查找对应的 Session,并获取用户信息。

Session 有一个过期时间,一般为 30 分钟或 1 小时。当用户在一段时间内没有操作网站时,Session 会过期并被销毁。此外,用户退出登录时,也需要销毁 Session。

需要注意的是,Session 存储在服务器端,因此对服务器的内存和性能有一定的影响。为了避免 Session 过多导致服务器崩溃,一般需要设置 Session 的过期时间,并定期清理过期的 Session。

Session ID 存储在 Cookie 中的方式与其他信息存储在 Cookie 中的方式相同,只是 Session ID 的名称和值不同。一般情况下,Session ID 的名称为 “JSESSIONID”,值为服务器生成的唯一的 Session ID。

需要注意的是,Session ID 存储在客户端的 Cookie 中,可能会被一些恶意程序获取,从而导致用户信息泄露的风险。因此,需要采取一些安全措施来保护 Session ID 的安全,如使用 HTTPS 协议传输数据、设置 HttpOnly 属性等。

优点

  • 安全性较高,Session信息存储在服务端,不容易被窃取和篡改。
  • 可以存储大量的信息,因为Session信息存储在服务端,不受客户端限制。
  • 可以设置过期时间,可以长期存储用户信息,不需要重复登录。

缺点

  • 使用Session需要占用服务端的资源,可能会影响系统的性能。
  • Session在多台服务器集群中需要进行共享,需要额外的配置和管理。

3、JWT (JSON Web Token)

img

token在服务器端只存储一个密钥或签名

  1. 用户通过登录页面输入用户名和密码,服务器验证用户的身份信息,并生成一个 token。
  2. 服务器将生成的 token 返回给客户端,并在客户端存储该 token。
  3. 当用户需要访问需要登录的页面时,客户端将 token 发送给服务器进行验证。
  4. 服务器验证 token 的有效性,如果有效则允许用户访问需要登录的页面。

这种方式可以避免用户每次访问需要登录的页面时都需要输入用户名和密码,提高用户体验。同时,token 的有效期可以设置,可以提高安全性。

优点

  • 安全性较高,Token信息存储在客户端,不容易被窃取和篡改。
  • 可以跨域使用,适用于前后端分离的应用程序。
  • 可以扩展为JWT(JSON Web Token),可以存储任意类型的数据。

缺点

  • Token存储在客户端,可能会被其他网站或应用程序获取到。
  • token 一旦由 server 生成,它就是有效的,直到过期,无法让 token 失效,除非在 server 为 token 设立一个黑名单。需要保证生成的Token的安全性。

TokenUtils:

package com.lxg.jwt.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class TokenUtil {

    private static final String SECRET_KEY = "(aud9h9.a!!)";

   /* public static String generateToken(String username,String password,String subject, long expiration) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", username);
        claims.put("password", password);
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }*/

    // 生成token
    public static String generateToken(Integer id, Integer scope, long expiration) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", id);
        claims.put("scope", scope);
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }

    // 获取token中的信息
    public static String getSubjectFromToken(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }


    // 获取token中的信息
    public static HashMap<String,Object> getClaimsFromToken(String token){
        Claims claims = Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
        HashMap<String,Object> map = new HashMap<>();
        map.put("username",claims.get("username"));
        map.put("password",claims.get("password"));
        return map;
    }

    // 验证token是否有效
    public static boolean isTokenValid(String token) {
        try {
            Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static void main(String[] args) {

//        String token = generateToken("xiaolin", "123456","test",864000);
//        String token = generateToken(1, 1,864000);
//        System.out.println("token="+token);
        String token = "eyJhbGciOiJIUzUxMiJ9.eyJzY29wZSI6MiwiaWQiOjEsImV4cCI6MTY4MTg3MTY5M30.XvPwLdmRKkuTP3g0GVCddGlIkM0Y-nT7gHDPi2C_68qWKlDZRi_nVDeMra0aVBSvv-s-skb7ll7eJHA10HTL6A";
        System.out.println("token="+token);
        boolean isValid = isTokenValid(token);
        System.out.println("isValid="+isValid);

        HashMap<String, Object> userMap = getClaimsFromToken(token);
        System.out.println("username="+userMap.get("username"));
        System.out.println("password="+userMap.get("password"));
        String test = getSubjectFromToken(token);

        System.out.println("test="+test);

    }
}

JWTInterceptor:

package com.lxg.jwt.controller.interceptor;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.lxg.jwt.utils.TokenUtil;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.HashMap;
import java.util.Map;

/**
 * JWT验证拦截器
 */
public class JWTInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Map<String,Object> map = new HashMap<>();
        //令牌建议是放在请求头中,获取请求头中令牌
        String token = request.getHeader("Authorization");
//        String token = null;
//        Cookie[] cookies = request.getCookies();
//        if (cookies != null) {
//            for (Cookie cookie : cookies) {
//                if ("token".equals(cookie.getName())) {
//                    token = cookie.getValue();
//                    // 处理token
//                    break;
//                }
//            }
//        }
        try{
            boolean tokenValid = TokenUtil.isTokenValid(token);//验证令牌
            if(tokenValid){
                //获取令牌中的用户信息
                HashMap<String, Object> claimsFromToken = TokenUtil.getClaimsFromToken(token);
                String username = (String) claimsFromToken.get("username");
                String password = (String) claimsFromToken.get("password");
                if (username.equals("xiaolin") && password.equals("123456")) {
                    return true;
                }else {
                    map.put("msg","token失效");
                }
            }
        }catch (Exception e){
            map.put("msg","token失效");
        }
        map.put("state",false);//设置状态
        //将map转化成json,response使用的是Jackson
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().print(json);
        return false;
    }
}

InterceptorConfig:

package com.lxg.jwt.controller.interceptor;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/api/login")
                .excludePathPatterns("/")
//                .excludePathPatterns("/api/verify")
                .excludePathPatterns("/css/**")
                .excludePathPatterns("/js/**");
    }
}
 .excludePathPatterns("/api/login")
            .excludePathPatterns("/")

// .excludePathPatterns(“/api/verify”)
.excludePathPatterns(“/css/“)
.excludePathPatterns(”/js/
”);
}
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值