多系统单一位置登录,实现多系统同时登录的一种技术。
单点登录一般用于互相授信的系统,实现单一登录,全系统有效。
三方登录:某系统,使用其他系统的用户,实现本系统登录的方式。解决信息孤岛,信息不对等的实现方案。
Session跨域
所谓Session跨域就是摒弃了系统提供的session,而使用自定义的类似session的机制来保存客户端数据的一种解决方案。
如:通过设置 cookie 的 domian 来实现 cookie 的跨域传递,在 cookie 中传递一个自定义的 session_id 。这个 session_id 是客户端的唯一标记。将这个标记为key,将客户端需要保存的数据作为 value ,在服务端保存(数据库保存或 NOSQL 保存)。这种机制就是Session跨域解决。
Cookie 中的domian属性,表示的是cookie所在的域,默认为请求的地址,如网址为www.baidu.com/test/a,那么domain默认为www.baidu.com。而跨域访问,如域A为 A.test.com ,域B为 B.test.com ,那么在域A生产一个令域A和域B都能访问的cookie就要将该cookie的domain设置为.test.com ;如果要在域A生产一个令域A不能访问而域B能访问的cookie就要将该cookie的domain设置为B.test.com 。
Spring Session共享
spring-session 技术是 spring 提供的用于处理集群会话共享的解决方案。spring-session 技术是将用户 session 数据保存到三方存储容器中,如:mysql、redis等。
spring-session 技术是解决同域名下的多服务器集群 session 共享问题的。不能解决跨域 session 共享问题。
Nginx Session 共享
nginx 中的 ip_hash 技术能够将某个 IP 的请求定向到同一台后端,这样依赖这个 ip 下的某个客户和某个后端就能建立器稳固的 session ,IP_HASH 是在 upstream 配置中定义的。
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream myserver{
server 127.0.0.1:8080 weight=5;
server 127.0.0.1:8081 weight=10;
ip_hash;
}
server {
listen 80;
server_name localhost;
location / {
root html;
proxy_pass http://myserver;
index index.html index.htm;
}
location = /50x.html {
root html;
}
}
}
ip_hash 是容易理解的,但是因为仅仅能用 IP 这个因子来分配后端,因此 ip_hash 是有缺陷的,不能在一些情况下使用:
nginx 不是最前端的服务器。ip_hash 要求nginx 一定是最前端的服务器,否则 nginx 得不到正确 ip ,就不能根据 IP 作 hash 。譬如使用的是 squid 为最前端,那么 nginx 取 ip 时只能却道 squid 的服务器 ip 地址,用这个地址来作分流时肯定错乱的。
nginx 的后端还有其他方式的负载均衡。假如 nginx 后端又又其他负载均衡,将请求又通过另外的方式分流了,那么某个客户端的请求肯定不能定位到同一台 session 应用服务器上。
Token 机制
使用token验证机制的优势是:
- 无状态,可扩展:
在客户端存储的 Token 是无状态的,并且能够被扩展。基于这种无状态的和不存储 session 信息,负载均衡器能够将用户信息从一台服务器传递到另外的服务器。 - 安全性:
请求中发送 token 而不是发送 cookie 能够防止 CSRF(跨站请求伪造)。即使在客户端使用 cookie 存储 token ,cookie 也仅仅是一个存储机制而不是用于认证,不将信息存储在 session 中,让我们少了对 session 的操作
JSON WEB TOKEN(JWT机制)
? JWT是一种紧凑 的且自包含的 ,用于在多方传递 JSON 对象的技术。传递的数据可以使用数字签名增加其安全性。可以使用HMAC 加密算法或RSA公钥/私钥 加密方式.
紧凑:数据小,可以通过URL,POST参数,请求发送。且数据小代表传输速度块。
自包含:使用 payload 数据块记录用户必要且不隐私的数据,可以有效的减少数据库访问次数,提高代码性能。
JWT一般用于处理用户身份验证 或数据信息交换
JWT结构
JWT 的数据结构是:A.B.C 由字符点 ‘.’ 来分隔三部分数据。
A-header 头信息
B-payload 载荷
C-Signature 签名
Header
# 数据结构:
{
"alg":"加密算法名称",
"typ":"JWT"
}
# alg 是加密算法定义内容,如:HMAC SHA256 或 RSA
# typ 是token类型,这里固定为 JWT
payload
在 payload 数据中一般用于记录实体(通常为用户信息)或其他数据的。主要分为三部分,分别是:已注册信息(registered claims),公开数据(public claims),私有数据(private claims)。
payload 中常用信息有:iss(发行者),exp(到期时间),sub(主题),aud(受众)等。这些都是以注册信息。
公开数据部分一般都会在JWT 注册表中增加定义。避免和已注册信息冲突。
公开数据和私有数据可以由程序员自行定义。
注意:即使 JWT 有签名加密机制,但是 payload 内容都是明文记录,除非记录的是加密数据,否则不排除泄密隐私数据的可能,不推荐在 payload 中记录任何敏感数据。
Signature
签名信息。这是一个由开发者提供的信息。是服务器验证的传递的数据是否安全有效的标准。在生成 JWT 最终数据之前。先使用 header 中定义加密算法,将 header 和 payload 进行加密,并使用点进行连接。如:加密后的 head.加密后的payload。再使用相同的加密算法,对加密后的数据和签名信息进行加密。得到最终结果。
JWT使用
maven依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
JWT工具类
public class JWTUtil {
private static final String SECRET_KEY = "test_web_ab";
private static final ObjectMapper MAPPER = new ObjectMapper();
private static byte[] getSecretKey() {
return SECRET_KEY.getBytes(StandardCharsets.UTF_8);
}
public static String createJWT(String id, String iss, String subject, Long ttlMillis) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
Long nowMillis = System.currentTimeMillis();
Date data = new Date(nowMillis);
Map<String, Object> claims = new HashMap<String, Object>();
claims.put("username", "李四");
claims.put("password", "1234567890");
JwtBuilder builder = Jwts.builder()
.setClaims(claims)
.setIssuedAt(data)
.signWith(signatureAlgorithm, getSecretKey());
if (ttlMillis >= 0) {
long l = nowMillis + ttlMillis;
Date exp = new Date(l);
builder.setExpiration(exp);
}
return builder.compact();
}
public static Claims analysisJWT(String token) {
return Jwts.parser()
.setSigningKey(getSecretKey())
.parseClaimsJws(token)
.getBody();
}
}
|