认证和授权
- 认证(Authentication): 你是谁,通过验证您的身份凭据(例如用户名/用户ID和密码),系统得以知道你就是你,也就是说系统存在你这个用户。
- 授权(Authorization):你有权限干什么,掌握了访问系统的权限。比如有些特定资源只能具有特定权限的人才能访问。
Cookie
Cookie是为了辨别用户信息而存储在本地终端的数据。存放在客户端,一般保存用来保存用户信息。
作用:
- 保存已经登录过的用户信息
- 保存Session或者Token,请求的时候会带上Cookie,这样后端就可以获取到Session或者Token了
- 用来记录和分析用户行为
- 设置Cookie
@GetMapping("addCookie")
public String addCookie(HttpServletResponse response){
Cookie cookie = new Cookie("username", "pluto");
// 过期时间1天
cookie.setMaxAge(24 * 60 * 60);
response.addCookie(cookie);
return "ok";
}
- 获取Cookie
@GetMapping("getCookie")
public String getCookie(@CookieValue(value = "username", defaultValue = "tong") String username){
return "cookie(username) value is : " + username;
}
Session
Session的主要作用就是通过服务端记录用户的状态。Cookie将数据保存在客户端(浏览器端),Session将数据保存在服务器端。相对来说Session安全性更高。如果使用Cookie的一些敏感信息不要写入Cookie中,最好能将Cookie信息加密然后使用到的时候再去服务器端解密。
Session进行身份验证:
- 用户向服务器发送用户名和密码用于登陆系统。
- 服务器验证通过后,服务器为用户创建一个Session,并将Session信息存储起来。
- 服务器向用户返回一个sessionId,写入用户的Cookie。
- 当用户保持登录状态时,Cookie将与每个后续请求一起被发送出去。
- 服务器可以将存储在Cookie上的sessionId与存储在内存中或者数据库中的Session信息进行比较,以验证用户的身份,返回给用户客户端响应信息的时候会附带用户当前的状态。
@GetMapping("getSession")
public String getSession(HttpServletRequest request, HttpServletResponse response){
HttpSession session = request.getSession();
session.setAttribute("3568121212", "tong");
// Session有效时间(秒) 一个小时
session.setMaxInactiveInterval(60 * 60);
System.out.println(session.getMaxInactiveInterval());
Cookie cookie = new Cookie("sessionId", "3568121212");
// 过期时间1天
cookie.setMaxAge(24 * 60 * 60);
response.addCookie(cookie);
return "ok";
}
@GetMapping("getUser")
public String getUser(HttpServletRequest request, HttpServletResponse response){
HttpSession session = request.getSession();
Optional<Cookie> first = Arrays.stream(request.getCookies()).
filter(cookie -> "sessionId".equals(cookie.getName())).findFirst();
Object attribute = session.getAttribute(first.get().getValue());
System.out.println(attribute);
return "ok";
}
Session缺陷
- 需要我们保证保存Session信息服务器的可用性
- 不适合移动端(依赖Cookie)等等
Cookie无法防止CSRF攻击
CSRF(Cross Site Request Forgery)一般被翻译为 跨站请求伪造
当我们通过Session认证的时候,我们一般使用Cookie来存储sessionId,当我们登陆后后端生成一个sessionId放在Cookie中返回给客户端,服务端通过Redis或者其他存储工具记录保存着这个sessionId,客户端登录以后每次请求都会带上这个sessionId,服务端通过这个sessionId来标识你这个人。如果别人通过Cookie拿到了sessionId后就可以代替你的身份访问系统了。所以,当你点击其他链接的时候,就会将自己的Cookie信息暴露给别人,别人就可以拿到sessionId信息。
Token
JWT(JSON Web Token),这种方式服务器端就不需要保存Session数据了,只用在客户端保存服务端返回给客户的Token就可以了,扩展性得到提升。JWT 本质上就一段签名的JSON格式的数据。由于它是带有签名的,因此接收者便可以验证它的真实性。
JWT由三部分构成:
-
Header(头部):描述JWT的元数据。定义了生成签名的算法以及Token的类型,通常是一个JSON对象
{ "alg": "SHA256" // 算法类型,这里默认是SHA256 "typ": "JWT" // Token类型,这里统一为JWT } -
Payload(负载):用来存放实际需要的数据,Payload也是一个JSON对象,官方定义了一些字段,还可以自己定义一些字段
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
-
Signature(签名):服务器通过Payload、Header和一个密钥(secret)使用Header里面指定的签名算法(默认是HMAC SHA256)生成
- 签名算法:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) - Token: 把Header、Payload、Signature三个部分拼成一个字符串,每个部分之间用"点"(.)分隔
- 签名算法:
数据格式,由逗号分隔成三部分:
在基于Token进行身份验证的的应用程序中,服务器通过Payload、Header和一个密钥(secret)创建令牌(Token)并将 Token 发送给客户端,客户端将Token保存在Cookie或者localStorage里面,以后客户端发出的所有请求都会携带这个令牌。你可以把它放在Cookie里面自动发送,但是这样不能跨域,所以更好的做法是放在HTTP Header的Authorization字段中: Authorization: Bearer Token。
JWT身份验证
- 用户向服务器发送用户名和密码用于登陆系统。
- 身份验证服务响应并返回了签名的 JWT,上面包含了用户是谁的内容。
- 用户以后每次向后端发请求都在Header中带上 JWT。
- 服务端检查 JWT 并从中获取用户相关信息。