2.单点登录(SSO)的设计与实现?

小龙coding大约 3 分钟

Redis+Jwt实现单点登录

功能描述

项目为前后端分离,微服务架构。利用 Redis+JWT实现了单点登录

业务流程分析

登录详细流程

1、用户输入账号、密码发起登录请求

2、前端调用后端接口 /api/auth/mcode 获取加密码(随便取得一个名,后台生成 mcode 后会将 mcode 设置 1分钟的过期时间存于 Reids中,方便后面验证)

3、前端使用 sh256 算法 对 password 加密后,再对(加密密码+mcode)进行加密 ===》sh256算法(sh256(password)+mcode)=mmpwd

密码:password
加密码:mcode
sh256(password):mpwd
sh256(sh256(password)+mcode)==mmpwd

4、发起登录请求 /api/auth/login ,params={mcode:xxx,username:xxxx,password:mmpwd}

5、网关拦截 检测 login请求 不在拦截范围 放行来到 auth 认证中心进行登录认证

6、根据用户名查询数据库获取mpwd(数据库存的密码是被sh256加密后的密码====》 sh256(password)=mpwd)

7、从 Redis 中获取 mcode,利用sh256(mpwd+code)计算得到的mmpwd' 和前端传来的 mmpwd 比较,相同则登录成功

8、生成JWT

9、将 JWT 存于 Redis,以 用户类型+产品码+工程ID+用户名+JWT 作为 Redis 的 key,JWT 作为 value存入 Redis

LoginType_Type(用户类型)_productCode(产品码)_projectId(工程Id)_username(用户名)+jwt(也就是存于header的token),JWt

10、将 key 存入 cookie,存于浏览器

git config --global user.email "2636702424@qq.com"

基本思路介绍

第一阶段

用户发起 登录请求 /api/auh/login

网关拦截 检测不在拦截范围 放行来到 auth 认证中心

根据 用户名密码 查询 MySQL 数据库

若用户存在则利生成 JWT

将 JWT 存于 Redis,以 用户类型+产品码+工程ID+用户名+JWT 作为 Redis 的 key,JWT 作为 value存入 Redis

LoginType_Type(用户类型)_productCode(产品码)_projectId(工程Id)_username(用户名)+jwt(也就是存于header的token),JWt

将 key 存入 cookie,存于浏览器

第二阶段

用户发起其他业务请求 /api/service/my

网关拦截 检测在拦截范围 进行登录验证

取出 cookie 中的 key,从 Redis 取出对应的 JWT 进行校验,通过则代表已登录 放行到其他微服务

第三阶段

通常其他微服务会做请求拦截

拦截器会从 cookie 取出 key 去 Redis 获取 Token 进行校验 并解析得到用户的基本信息 UserInfo

将解析得到的 UserInfo 存于 本地线程变量(ThreadLocal)中

后面业务处理可以将用户基本信息从本地线程变量(ThreadLocal)取出

面试分析

1、为什么 key 要这样设计?

企业级项目考虑系统可能用多种用户类型、不同的子系统等,因此 key 的拼接参数会有很多标识进行拼接,可以根据自己的项目情况选取。

2、为什么 key 前面有了唯一标识串 (用户类型+产品码+工程ID+用户名)后面还要拼接 JWT

用户可能在不同的地方进行登录,每次生成的 JWT 不一样,同一个用户也可能有多个 JWT,因此还需要在后面拼接 JWT 对相同用户进行区分。

3、退出登录怎样实现?

退出登录也就是将 Redis 里存的 JWT 删除即可,但是一个用户可能在不同的地方进行登录,一个用户可能有多个 JWT存于Redis。

因此退出登录,从 Redis 缓存中删除用户 Token 信息时需要正则模糊删除(LoginType_type_productCode_projectId_username_*),前面那串相同用户是一样的。

问题拓展

1、Redis 模糊匹配查询怎样做?

redisTemplate.keys(【正则表达式】

4、Redis 的内存空间是十分宝贵的,你这随着时间推移,用户增加 Redis 存的 JWT 不会越来越多吗?

登录是有过期时间的,Redis 在存 JWT 时会设置一个合理的过期时间。

并且,正常逻辑是用户在进行系统访问操作时,应该对过期时间进行刷新。