Use of Cookie, Session, Token, Jwt

Use of Cookie, Session, Token, Jwt


Both can be used to get user login status.

1. Cookies

The cookie is created on the server side but saved on the client browser until the end of the session expires (expiration time can be set), and every time a request is initiated, it will visit the server with all the cookies of the browser.
Test using code:

@Controller
@RequestMapping("cookie")
public class CookieDemo {
    
    

    //测试cookie使用
    @RequestMapping("c")
    @ResponseBody
    public void test(HttpServletRequest request, HttpServletResponse response) throws IOException {
    
    
        request.setCharacterEncoding("GBK");          //设置请求编码格式
        response.setCharacterEncoding("GBK");        //设置响应编码格式
        response.setContentType("text/html;charset=utf-8");     //设置响应格式(不然要返回一个文档什么的显示不了)
        PrintWriter out = response.getWriter();
        Cookie[] cookies = request.getCookies();     //获取客户端请求中的cookie
        if(cookies!=null){
    
                              //判断是否有cookie
            out.write("你上一次访问时间是:");
            for (int i = 0; i < cookies.length; i++) {
    
                               //遍历所有cookie
                Cookie cookie = cookies[i];
                if (cookie.getName().equals("lastLoginTime3")){
    
                     //获取cookie名字
                    long lastLoginTime = Long.parseLong(cookie.getValue());     //将cookie的value值转成长整形
                    Date date = new Date(lastLoginTime);                        //将长整形转化为日期格式
                    out.write(date.toLocaleString());
                }
            }
        }else {
    
    
                    out.write("这是您第一次访问本站");
        }
        Cookie cookie = new Cookie("lastLoginTime3", System.currentTimeMillis() + "");
        //cookie.setMaxAge(60*60*24);     //设置cookie存活时间为一天(如果不设置就是关闭浏览器自动删除cookie,设为0也能理解为删除)
        response.addCookie(cookie);       //给客户端响应一个cookie
    }

}

video

2. Session

The session is created on the server side. After the session object is created, it will be saved on the server until the end of the session, and the ID of the session object will be returned to the browser in the form of a cookie, so that the browser will carry the session with each request. In the past, the server will first check whether there is a sessionId in the request. If there is no sessionId, a session object will be created; if there is a sessionId, then the corresponding session object will be searched according to the sessionId. If not found, create a new session object. (different browser requests will first create a session object)
test code:

@Controller
@RequestMapping("session")
public class SessionDemo {
    
    

    //测试session使用
    @RequestMapping("c")
    @ResponseBody
    public void test(HttpServletRequest request, HttpServletResponse response) throws IOException {
    
    
        request.setCharacterEncoding("GBK");          //设置请求编码格式
        response.setCharacterEncoding("GBK");        //设置响应编码格式
        response.setContentType("text/html;charset=utf-8");     //设置响应格式(不然要返回一个文档什么的显示不了)

        HttpSession session = request.getSession();     //先查看请求当中是否有sessionId,如果没有sessionId,则创建一个session对象;如果有sessionId,则依据该sessionId去查找对应的session对象,如果找到了,则返回该session对象,如果没有找到,则创建一个新的session对象。(相当不同的浏览器请求发过来都会先创建一个session对象)
        // Session创建的时候微了什么事情;   Cookie cookie = new Cookie( "JSESSIONID",sessionId);response.addCookie(cookie);
        long o = System.currentTimeMillis();
        session.setAttribute("date", o);		//设置这个session的key和value
        String sessionId = session.getId();     //获取session的id
        if (session.isNew()){
    
                       //判断session是不是新创建的
            response.getWriter().write("session创建成功,ID:"+sessionId);
        }else {
    
    
            response.getWriter().write("session已经在服务器中存在,ID:"+sessionId);
        }
        //session.invalidate();  注销session相当于关闭浏览器的操作
    }
}

Summary: The session is only valid for one session (you can also set the session expiration time). When the browser is closed and revisited, the server will create a new session object and save it in memory. When the user visits a lot, consider the server In terms of performance, it is more appropriate to use cookies (because cookies are stored on the client), but Session has a fatal disadvantage that server clusters cannot be shared, and requests may be sent to different servers after load balancing, so it needs to be used with Redis.

video

3.Token

The session mechanism (Session) is one of the methods for identifying the user identity, but due to the need for the server to save the session id of all people, if there are many access servers, there must be tens of thousands or hundreds of thousands. This is a huge overhead for the server, which seriously limits the expansion capability of the server. Thus was born the token (token).

Token authentication process:

  1. The user enters the username and password and sends them to the server.

  2. The server verifies the user name and password, and if it is correct, returns a signed token and stores it in the redis database (the token can be considered as a long string, or uuid can be used as the token), and the browser client gets the token.

  3. In each subsequent request, the browser will send the token as an HTTP header to the server, and the server will obtain the token in the request header and query the redis database for the existence of the token.

  4. If it exists, return the data required by the client. Features: The feature of this method is that the client's token retains a lot of information, and the server does not store this information.

  5. Change the filter information, obtain the token value in the request header, and compare it with the value in redis. If the value is the same, the expiration time of the token in redis will be updated when the pass is released.

  6. The front end saves the token value ( stored in localStorage ), and lets the request header carry the token value
    to set the attribute in ajax –> beforeSend: function (XMLHttpRequest) { XMLHttpRequest.setRequestHeader(“token”, “token’s value”); } 7. Logout Function (logout): delete the token value in localStorage (front end) and redis (back end).


(login) sample code:

//使用token前先把redis配置好并启动
@Controller
@RequestMapping("token")
public class TokenDemo {
    
    

    @Autowired
    @Qualifier("redisTemplate")      //使用自己的redisTemplate
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisUtil redisUtil;    //使用封装好的redis工具类

    //测试Token使用(需要用到Redis)
    @RequestMapping("c")
    @ResponseBody
    public String test(@RequestParam String userName,@RequestParam String passWord){
    
    
        String MysqlUserName = "cjy";       //模拟数据库账号
        String MysqlPassWord = "123456";    //模拟数据库密码
        if (userName.equals(MysqlUserName)&&passWord.equals(MysqlPassWord)){
    
       //登录成功
            String token = UUID.randomUUID()+"";         //生成令牌
            redisUtil.set(token,userName,60*30);  //存入redis中,key为token,value为用户名(也可以是一个对象),过期时间设为30分钟
            return token;
        }
        return "登录失败!";
    }
}

Disadvantages of using Token : Every time you need to query the real content in the backend redis according to the token, the pressure on the server will be great.

video

四.JWT(Json Web Token)

Jwt is a string composed of the following three parts: (Header and Payload data are formed by Base64 encoding, and Verify signature is encrypted by MD5)
Please add a picture description

  1. Header: store the type of encryption algorithm
    Example:
    { Typ="jwt" --------> type is jwt Alg="HS256" --------> encryption algorithm is hs256 }


  2. Payload (payload –> loaded data): It is the data content stored in jwt, which is the value of the token stored in the redis database (it is not recommended to store some sensitive data such as passWord, phoneNumber, etc., because the data is stored directly on the client , not safe)
    Example:
    { "userName": "cjy" "birthday": "1999-11-20" "expiration time": "Thursday April 13, 2023 3:25:17 pm" }



Common attribute names are as follows:

iss: jwt issuer
sub: jwt-oriented user
aud: the party that receives jwt
exp; the expiration time of jwt, which must be greater than the issue time
nbf: defines when the jwt is unavailable
iat: The jwt issuance time
jti: the unique identity of the jwt, which is mainly used as a one-time token to avoid replay attacks.

  1. Verify signature: To prevent others from tampering with the data in the Payload,
    this part of the data is returned after splicing the data in the Payload with a signature (adding salt) and encrypting it with MD5. The data encrypted by MD5 is irreversible, so After returning to the front end, if the data is changed and passed to the back end, the Jwt will fail to parse.

Jwt authentication process

  1. The user enters the username and password and sends them to the server.

  2. Check whether the user name and password are correct. If they pass the Jwt encryption algorithm correctly, put the user information into the Jwt and return it to the client (browser) for storage (it can be stored in a cookie or localStorage).

  3. In each subsequent request, the browser will send the Jwt as an http header to the server, and the server will directly parse the Jwt.

  4. If the parsing is successful, it means that the token is valid, otherwise it is invalid (if the Jwt is tampered with, the parsing will fail), and the information stored in the Jwt can be used directly after the parsing is successful

Handwritten jwt according to the principle (just understand)

@Controller
@RequestMapping("jwt")
public class JwtDemo {
    
    

    //手写Jwt案例
    @Test
    public void Jwt() throws UnsupportedEncodingException {
    
    

        //header
        JSONObject heafer = new JSONObject();
        heafer.put("Alg","HS256");
        //payload
        JSONObject payload = new JSONObject();
        payload.put("userName","cjy");
        payload.put("userAge","23");
        payload.put("userId","1564");
        //payload.put("sjs", System.currentTimeMillis());      //设置随机数让每次生成的payload不一样
        //对数据进行base64编码
        String jwtHeader = Base64.getEncoder().encodeToString(heafer.toJSONString().getBytes());
        String jwtPayLoad = Base64.getEncoder().encodeToString(payload.toJSONString().getBytes());
        //设置盐值(一般情况下都是设置随机的盐值)
        String signingKey = "cjy";
        //签名 后面加盐(秘钥) (是存放在服务器端) (不加盐的话有可能会被暴力破解)
        String sign = MD5Utils.md5(payload.toJSONString() + signingKey);
        String jwt = jwtHeader + "."+ jwtPayLoad + "." + sign;      //拼接生成jwt
        System.out.println(jwt);

        //解密(判断前端中jwt的payload是否被更改)
        String jwtPayloadStr = jwt.split("\\.")[1];       //获取jwt中的payload的值
        String jwtSignStr = jwt.split("\\.")[2];          //获取jwt中签名的值
        //payload进行base64解码
        String deJwtPayloadStr = new String(Base64.getDecoder().decode(jwtPayloadStr), "UTF-8");
        System.out.println(MD5Utils.md5(deJwtPayloadStr + signingKey).equals(jwtSignStr));

    }
}

real steps

  1. Introduce pom dependencies
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.6.0</version>
</dependency>
  1. Create jwt after successful login verification
@Controller
@RequestMapping("jwt")
public class JwtUseDemo {
    
    

    private long time = 1000 * 60 * 60 * 24; //定义jwt存活时间为一天
    private String signature = "admin";     //定义签名信息(盐值)

    //Jwt使用案例
    @Test
    public void createJwt(){
    
    
        JwtBuilder jwtbuilder = Jwts.builder(); //创建一个jwt
        String jwtToken = jwtbuilder
                //header
                .setHeaderParam("typ","JWT")
                .setHeaderParam("alg","HS256")
                //payload
                .claim("userName","cjy")
                .claim("role","admin")
                .setSubject("admin-test")
                .setExpiration(new Date(System.currentTimeMillis()+time))
                .setId(UUID.randomUUID().toString())
                //signature(签名)
                .signWith(SignatureAlgorithm.HS256,signature)
                //凭借字符串
                .compact();
        System.out.println("生成的jwt值为:"+ jwtToken);
    }
}
  1. Decrypt jwt and get the value in payload
@Controller
@RequestMapping("dejwt")
public class JwtUseDemo {
    
    
    private String signature = "admin";     //定义签名信息(盐值)
    //jwt解密
    @Test
    public void DecodeJwt(){
    
    
        String jwtStr = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6ImNqeSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2NDk5OTQ4MjIsImp0aSI6IjE4YzdkZDI0LTAzMTUtNDI1Yi04NGMxLTQzNzg5MTk2NGExMyJ9.Ku1xIM6SG7utEFxvQF_eURSY1-tkG7om_zT4DDomyN0";
        JwtParser jwtParser = Jwts.parser();    //通过这个对象进行解密
        //传入签名(盐值)对jwt进行解密并返回payload集合
        Jws<Claims> claimsJws = jwtParser.setSigningKey(signature).parseClaimsJws(jwtStr);
        //取得集合里的数据
        Claims claims = claimsJws.getBody();
        System.out.println(claims.get("userName"));
        System.out.println(claims.get("role"));
        System.out.println(claims.getId());
        System.out.println(claims.getSubject());
        System.out.println(claims.getExpiration());
    }
}

Jwt itself is an optimized version of Token. The authentication process is almost the same, except that it is encrypted when generating token. After successful parsing, the information in Jwt can be directly used in most cases.

The biggest difference between Jwt and token:
token depends on Redis to query data information, and it is safer to store value data in token (because the data stored in redis cannot be connected to other servers and the key is a unique token value, it is difficult to obtain its value) .
And Jwt does not need to rely on the server side, it stores the data information directly on the client side (browser).

JwtAdvantages:

  • There is no need to store user data on the server, reducing server-side pressure
  • Lightweight, simple json style, cross-language

Disadvantages of Jwt:

  • Once the token is generated, it cannot be modified later, nor can the validity period of the token be updated
  • A jwt cannot be destroyed (so it is recommended to set the jwt survival time to be shorter)

Video 1 (understand the principle) Video 2 (real use)

Guess you like

Origin blog.csdn.net/cc1373709409/article/details/124116725