概要
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机制的基本使用方法:
@Controllerpublic classCookieTest {
@ResponseBody
@RequestMapping(value= "/get",method =RequestMethod.GET)publicString test(HttpSession session){
String value= String.valueOf(session.getAttribute("g"));
System.out.println(value);return "cookie";
}
@ResponseBody
@RequestMapping(value= "/add",method =RequestMethod.GET)publicString 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的基本使用
引入依赖
org.springframework.session
spring-session-data-redis
配置yml文件(先在本地安装redis,之后启动redis-server)
spring:
redis:
host: localhost
database:0port:6379lettuce:
pool:
min-idle: 5max-idle: 8max-active: 8max-wait: 1ms
shutdown-timeout: 100ms
代码测试
@RestControllerpublic classSessionTest {
@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基本使用
参考文章:
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