java基础之----cookie,session,jwt
概要
web中为什么要引入cookie、session机制,为了验证用户的身份,验证用户的身份是为了系统的安全,那如果是系统和系统之间的API调用怎么办呢?因为系统之间调用往往是没有用户系统的(用户系统就是使用用户名,密码机制),这时就出现了JWT,下面详细说明cookie,session,JWT的流程,原理和代码演示。
cookie,session机制原理
首先,cookie是浏览器保存的,session是服务器保存的,那cookie和session有什么关系呢?如下,当用户首次访问的时候,服务器会为用户的这次会话建立一个session,每个session都有一个独立的session id,当服务器响应浏览器的时候会把这个sessionid返回到浏览器,返回到浏览器放到哪里呢,放到cookie中,为什么要放到cookie中呢?因为用户下次再访问这个网站的时候需要把这个session id放到请求参数中,也就是说这个cookie是每次用户访问服务器都要带上的。
session超时的问题?
用户每次访问服务器,服务端都会自动为session超时时间续签,session默认的超时时间是30分钟。
session共享的问题?
如果服务端只有一个节点,就不存在共享问题,只有当服务端部署成分布式,才会有session共享的问题,那怎么实现session共享呢?目前主流的做法是使用redis把session缓存起来,所有节点每次都读取这个session就实现了session共享,spring-session已经把这种方式集成进来,后续会有例子。
JWT原理
jwt的验证一般来说是无状态的,什么叫无状态呢?在cookie-session机制中,服务器需要保存session,这种就是有状态的,而jwt机制,服务器不会保存这种信息,那jwt怎么实现权限认证呢?要弄清楚这个问题,需要先搞清楚jwt的组成,jwt由3部分组成,分别为:header(头部)、payload(载荷)、signature(签名),下面举个例子介绍这3个东东是什么。
header往往是这个样子:
{
"alg": "HS256",
"typ": "JWT"
}
上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT。
最后,将上面的 JSON 对象使用 Base64URL 算法(详见后文)转成字符串。
payload往往是这个样子:
{ "sub": "1234567890", "name": "John Doe", "admin": true }
注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
这个 JSON 对象也要使用 Base64URL 算法转成字符串。
signature往往这样子:
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。
代码示例
session-cookie机制的基本使用方法:
@Controller public class CookieTest { @ResponseBody @RequestMapping(value = "/get",method = RequestMethod.GET) public String test(HttpSession session){ String value = String.valueOf(session.getAttribute("g")); System.out.println(value); return "cookie"; } @ResponseBody @RequestMapping(value = "/add",method = RequestMethod.GET) public String cookieTest(HttpServletResponse response, HttpSession session){ Cookie cookie= new Cookie("asdf","asfd"); response.addCookie(cookie); session.setAttribute("g","niubi"); session.setMaxInactiveInterval(2000); return "cookie"; } }
spring-session的基本使用
引入依赖
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId>
</dependency>
配置yml文件(先在本地安装redis,之后启动redis-server)
spring: redis: host: localhost database: 0 port: 6379 lettuce: pool: min-idle: 5 max-idle: 8 max-active: 8 max-wait: 1ms shutdown-timeout: 100ms
代码测试
@RestController public class SessionTest { @RequestMapping("/set") String set(HttpServletRequest req, HttpServletResponse response) { req.getSession().setAttribute("testKey","niubi"); return "设置session:testKey=niubi"; } @RequestMapping("/query") String query(HttpServletRequest req) { Object value = req.getSession().getAttribute("testKey"); return "查询Session:\"testKey\"=" + value; } }
在请求完set方法之后可以去redis中看一下,会发现多出了三个key,有兴趣的可以了解一下每个key的作用,参考这篇文章
jwt基本使用
看这个大佬的例子:https://github.com/hyrepo/jwt-demo
参考文章:
http://blog.didispace.com/tags/Spring-Session/
http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
https://github.com/hyrepo/jwt-demo