分布式系统必懂——SSO单点登录
分布式系统单点登录
- 传统用户身份验证:
- 解决办法
- JWT
- JWT令牌类型:
- JWT的组成:
- JWT头
- 有效载荷
- 签名哈希
- Base64URL算法
- JWT的原则
- JWT的用法
- JWT问题和趋势
- 整合JWT令牌:
- 1、在模块中添加jwt工具依赖
- 2、创建JWT工具类
分布式系统单点登录:
在多个服务模块中,仅在一个模块中登录即可访问其它模块。
举例:豆瓣FM有自己的session、豆瓣读书有自己的session,而记录ID的cookie又是不能跨域的。这样用户的体验会非常的差,在使用同一家服务的同时需要多次登录。所以,我们要实现一次登录一次退出,只需要想办法让各个server的共用一个session的信息,让客户端在各个域名下都能持有这个ID就好了。而单点登录SSO就是为了解决这种问题。
传统用户身份验证:
Internet服务无法与用户身份验证分开。一般过程如下:
- 用户向服务器发送用户名和密码。
- 验证服务器后,相关数据(如用户角色,登录时间等)将保存在当前会话中。
- 服务器向用户返回session_id,session信息都会写入到用户的Cookie。
- 用户的每个后续请求都将通过在Cookie中取出session_id传给服务器。
- 服务器收到session_id并对比之前保存的数据,确认用户的身份。
这种模式最大的问题是,没有分布式架构,无法支持横向扩展。
解决办法
下面是实现单点登录(用户身份验证)的三个解决方法:
第一种:比较原始,目前使用较少,通过session复制会造成内存的大量浪费,不利于大量用户访问。
第二三种:目前使用较多,具体实现思路见下图
JWT
JWT:(全称:Json Web Token)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。JWT是Token令牌登录的一种解决方案。(上面的第三种)
上面说法比较文绉绉,简单点说就是一种认证机制,让后台知道该请求是来自于受信的客户端。
JWT令牌类型:
JWT的组成:
该对象为一个很长的字符串,字符之间通过"."分隔符分为三个子串。
每一个子串表示了一个功能块,总共有以下三个部分:JWT头、有效载荷和签名
JWT头
JWT头部分是一个描述JWT元数据的JSON对象,通常如下所示。
{"alg": "HS256","typ": "JWT"
}
在上面的代码中,alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT。最后,使用Base64 URL算法将上述JSON对象转换为字符串保存。
有效载荷
有效载荷部分,是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。 JWT指定七个默认字段供选择。
iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
除以上默认字段外,我们还可以自定义私有字段,如下例:
{"sub": "1234567890","name": "Helen","admin": true
}
请注意,默认情况下JWT是未加密的,任何人都可以解读其内容,因此不要构建隐私信息字段,存放保密信息,以防止信息泄露。
JSON对象也使用Base64 URL算法转换为字符串保存。
签名哈希
签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。
首先,需要指定一个密码(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。
然后,使用标头中指定的签名算法(默认情况下为HMAC SHA256)根据以下公式生成签名。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(claims), secret)
在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象。
Base64URL算法
如前所述,JWT头和有效载荷序列化的算法都用到了Base64URL。该算法和常见Base64算法类似,稍有差别。
作为令牌的JWT可以放在URL中(例如api.example/?token=xxx)。 Base64中用的三个字符是"+“,”/“和”=“,由于在URL中有特殊含义,因此Base64URL中对他们做了替换:”=“去掉,”+“用”-“替换,”/“用”_"替换,这就是Base64URL算法。
JWT的原则
JWT的原则是在服务器身份验证之后,将生成一个JSON对象并将其发送回用户,如下所示。
{"sub": "1234567890","name": "Helen","admin": true
}
之后,当用户与服务器通信时,客户在请求中发回JSON对象。服务器仅依赖于这个JSON对象来标识用户。为了防止用户篡改数据,服务器将在生成对象时添加签名。
服务器不保存任何会话数据,即服务器变为无状态,使其更容易扩展。
JWT的用法
客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中。
此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域,因此一般是将它放入HTTP请求的Header Authorization字段中。当跨域时,也可以将JWT被放置于POST请求的数据主体中。
JWT问题和趋势
JWT不仅可用于认证,还可用于信息交换。善用JWT有助于减少服务器请求数据库的次数。
生产的token可以包含基本信息,比如id、用户昵称、头像等信息,避免再次查库
存储在客户端,不占用服务端的内存资源
JWT默认不加密,但可以加密。生成原始令牌后,可以再次对其进行加密。
当JWT未加密时,一些私密数据无法通过JWT传输。
JWT的最大缺点是服务器不保存会话状态,所以在使用期间不可能取消令牌或更改令牌的权限。也就是说,一旦JWT签发,在有效期内将会一直有效。
JWT本身包含认证信息,token是经过base64编码,所以可以解码,因此token加密前的对象不应该包含敏感信息,一旦信息泄露,任何人都可以获得令牌的所有权限。为了减少盗用,JWT的有效期不宜设置太长。对于某些重要操作,用户在使用时应该每次都进行进行身份验证。
为了减少盗用和窃取,JWT不建议使用HTTP协议来传输代码,而是使用加密的HTTPS协议进行传输。
整合JWT令牌:
1、在模块中添加jwt工具依赖
在pom中添加
<dependencies><!-- JWT--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId></dependency>
</dependencies>
2、创建JWT工具类
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;
/*** @author*/
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;}
/*** 判断token是否存在与有效* @param jwtToken* @return*/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;}
/*** 判断token是否存在与有效* @param request* @return*/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;}
/*** 根据token获取会员id* @param request* @return*/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");}
}
分布式系统必懂——SSO单点登录相关推荐
- 上手实操分布式系统下的SSO单点登录
分布式核心问题系列目录 分布式核心问题 - SSO单点登录 分布式核心问题 - 分布式锁 分布式核心问题 - 分布式接口幂等性设计 分布式核心问题 - MyCat实现读写分离 ------------ ...
- CAS SSO 单点登录 【完整版】
什么是单点登录?什么是SSO? SSO就是单点登录!!! SSO即Single Sign On. 可是为什么我们要单点登录呢?为什么不能把所有的系统做成一个war包里呢? 道理很简单啊,如果这个银行这 ...
- SpringCloud入门 —— SSO 单点登录
前言 本文适合初学者,如有不足或错误之处,还请大家在下方留言指正.(文章稍长,建议点赞收藏) 一.SSO单点登录是什么? 单点登录简介 单点登录SSO (Single Sign On) 是指在一个多系 ...
- SSO单点登录教程案例 客户端和服务端
这里写自定义目录标题 前言 条件 环境要求 准备工作 下载基础项目 项目结构说明 执行流程图 代码实现 单点登录步骤梳理: 代码下载 前言 文章摘抄:https://www.jianshu.com/p ...
- 逛淘宝天猫想到SSO单点登录
在前面文章中,我们聊了自建账号体系的注册和登录: 注册登录原理及密码安全问题(链接) 也聊了利用微信和QQ进行第三方登录,并详细讲述了原理和流程: 第三方账号登录的原理(链接) 然后,有朋友留言问到了 ...
- SSO单点登录教程(四)自己动手写SSO单点登录服务端和客户端
作者:蓝雄威,叩丁狼教育高级讲师.原创文章,转载请注明出处. 一.前言 我们自己动手写单点登录的服务端目的是为了加深对单点登录的理解.如果你们公司想实现单点登录/单点注销功能,推荐使用开源的单点登录框 ...
- SSO单点登录详解-------二、单点登录流程解析
一.简介 单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统. 二 ...
- Spring Cloud云架构 - SSO单点登录之OAuth2.0登录流程(2)
上一篇是站在巨人的肩膀上去研究OAuth2.0,也是为了快速帮助大家认识OAuth2.0,闲话少说,我根据框架中OAuth2.0的使用总结,画了一个简单的流程图(根据用户名+密码实现OAuth2.0的 ...
- [精华][推荐]CAS SSO单点登录服务端客户端学习
1.了解单点登录 SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用(多 ...
最新文章
- 眼耳鼻舌身意,严肃地聊一聊元宇宙的“技术拼图”
- jdbc驱动_JDBC概述和CRUD
- mysql表结构说明只能为1 8_SQL基础
- Java和WebSocket开发网页聊天室
- 贷款,别相信这些人!
- C++多线程实例(_beginThreadex创建多线程)
- C语言 | 直接插入排序
- 江西理工大学南昌校区cool code竞赛
- android学习笔记30——AndroidMainfest.xml
- D37 682. Baseball Game
- python输出99乘法表_如何用python输出99乘法表
- Intelliok IDEA的Monokai主题
- could not open `C:\Program Files\Java\jre7\lib\amd64\jvm.cfg' 的解决办法:
- 使用U盘制作纯dos系统
- java后台设置定时执行任务,Java定时任务调度详解
- java定时执行 web_定时执行任务-Java WEB程序【绝对好用】
- 怎么理解本征无序态的蛋白质(Intrinsically disordered proteins)
- [网络流24题] 洛谷P3356 火星探险问题 费用流
- 支付宝服务商条码付,直接打款给签约子商户方法
- 比光刻机还重要的IP核是什么?