单点登录介绍
单一服务器模式
使用session对象实现登录
登陆成功之后,把用户数据放到session中
判断是否登录,可以从session中获取数据,获得登录状态
但是session模式有缺点,因为session在不同的服务器中不能共享,所以这就导致我们在不同的服务器上需要重复登录,这一点是非常不好的
我们想要的结果是在一个服务器上登录,其他服务器全部共享。
这个有一个术语,叫做单点登录
SSO模式
SSO,Single Sign On,中文名叫做单点登录
单点登录有很多种实现方式,这里来介绍一下三种比较常见的机制:
第一种:session广播
session广播其实就是session的复制过程,它的大体流程是:先在一个服务器上进行登录,然后在另一台服务器上复制这台服务器上的session,这样就达到了所有信息在所有服务器上共享,达到单点登录的效果
但是虽然可以做到,但是有一个致命的缺点:假如我们有几十个模块,难道要进行复制几十次么?这是对资源的极大消耗,所以这个方法在几台服务器的时候还可以用一下,其他情况不太好使
第二种:cookie+redis
cookie,是一种客户端技术,也就是存到浏览器中,每次发送请求都会带着cookie发送
redis,是一种内存数据库,而且是基于key-value的存储
所以它的存储过程是这样的:
1、用户登录
用户登录成功之后,将数据放到两个地方:cookie和redis
对于redis,我们的value存储的就是用户信息,我们的key存储的是一个随机生成的唯一id(一般来讲有些人喜欢根据id,ip等等生成)
对于cookie,我们存储这个redis的key值
2、访问项目中的其他模块,发送请求时带着cookie
cookie中含有redis的key,我们拿着cookie值去查询是否能查询到value,如果能查询到就成功登陆
第三种:token
token,也叫令牌,它是按照一定的规则生成的字符串,字符串里包含用户信息
1、登录时
比如我们可以把用户信息做个编码,然后加密一下,这就是token,至于怎么编码,怎么加密就是你自己的问题
最后的这个字符串返回,你可以放到cookie里面,或者地址栏里面,或者请求头里面等等,反正只要返回即可
2、在其他服务器上
我们每次带着token发送到后端,后端解码获取用户信息,假如可以获取到用户信息,那么就说明登录成功,假如获取不到就说明登录失败
而且我们还有一个内容,session本来有一个默认的过期时间:30分钟
我们的第二种和第三种也可以设置过期时间
第二种:redis和token也可以设置过期时间,达到和session一样的效果
JWT
JWT概述
我们刚才讲到,token是按照一定的规则封装信息。这里有一个术语叫做自包含令牌
我们说按照一定规则,这个规则每个人想到的都不一样,根据这个,有一个比较通用的规则:JWT,所以JWT把规则已经给我们规定好了
图中的这一长串字符串就是我们的规则
- 红色部分:固定的,JWT头信息
- 紫色部分:有效载荷:包含主体信息(用户信息)
- 蓝色部分:签名哈希,防伪标志
JWT使用
1、引入依赖
1 2 3 4 5
| <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> </dependency>
|
2、使用JWT的工具类,这个工具类要会改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest; import java.util.Date;
public class JwtUtils { public static final long EXPIRE = 1000 * 60 * 60 * 24; public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";
public static String getJwtToken(String id, String nickname){
String JwtToken = Jwts.builder()
.setHeaderParam("typ", "JWT") .setHeaderParam("alg", "HS256")
.setSubject("guli-user") .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + EXPIRE)) .claim("id", id) .claim("nickname", nickname) .signWith(SignatureAlgorithm.HS256, APP_SECRET) .compact();
return JwtToken; }
public static boolean checkToken(String jwtToken) { if(StringUtils.isEmpty(jwtToken)) return false; try { Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken); } catch (Exception e) { e.printStackTrace(); return false; } return true; }
public static boolean checkToken(HttpServletRequest request) { try { String jwtToken = request.getHeader("token"); if(StringUtils.isEmpty(jwtToken)) return false; Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken); } catch (Exception e) { e.printStackTrace(); return false; } return true; }
public static String getMemberIdByJwtToken(HttpServletRequest request) { String jwtToken = request.getHeader("token"); if(StringUtils.isEmpty(jwtToken)) return ""; Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken); Claims claims = claimsJws.getBody(); return (String)claims.get("id"); } }
|