[前端]单点登录 SSO

1. 什么是单点登录?

单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

2. 单点登录的模式

2.1 模式一: session + cookie 模式

在这里插入图片描述

  1. 用户登录
  2. 认证中心获取用户数据,在 session 表中建立 sessionId 与用户信息的键值对
  3. 将 sessionId 以 cookie 的形式返回返回用户,并保存在客户端
  4. 当用户访问系统 A 时,将 cookie 中的 sessionId 附带在请求头中进行数据请求
  5. 系统 A 获取到用于户的 sessionId,需要去认证中心验证 sessionId,看用户是否登录或者登录是否过期
  6. 认证中心验证 sessionId 是有效的,返回验证结果,也可以附带用户身份信息到系统 A
  7. 系统 A 接收到认证中心的有效验证,将用户访问的受保护的资源响应给客户端
  8. 对其他系统的访问也是一样
优势:

认证中心对用户有着非常强的控制力:如果某个用户违规了不让其继续使用系统了,可以在认证中心维护的 session 记录中清除该用户的 sessionId,当用户请求系统时 sessionId 验证不通过,就会要求重新登录,如果配合黑名单使用控制会更灵活。

劣势:

认证中心压力大
系统登录和所有的请求验证都需要认证中心验证

花费大,代价高

  • 储存用户 session 信息,如果系统用户非常大,需要做 session 集群。
  • 认证中心管控登录及所有的请求验证,如果挂了,整个系统都不能用了,需要做容灾。
  • 如果某个系统需要扩容,认证中心也跟着需要扩容。

2.2 模式二:token 模式

在这里插入图片描述

  1. 用户登录
  2. 登录成功,认证中心生成一个不能被篡改的字符串 token,返回给用户并保存在客户端。
  3. 用户访问系统 A,会在请求头(或者 url 中)中附带 token 信息,系统 A 可以自行进行验证 token
  4. 系统 A 验证通过,返回系统受保护的资源给客户端
  5. 对其他系统的访问也是一样
优势:
  • 认证中心的压力减少了,只需要进行注册登录,不需要进行请求验证了,子系统可以自行验证,减少了认证中心的压力。
  • 花费减少了,认证中心不需要维护 sessionId 记录了。请求不需要对认证中心的验证,对认证心中的要求也不那么高了。子系统扩容也不会影响认证中心了。
劣势:

认证中心失去了对用户的控制,用户登录之后不需要经过认证中心就可以访问系统资源了。

2.3 模式二的升级:token + refreshtoken(双 Token)模式

在这里插入图片描述
在这里插入图片描述

  1. 用户登录
  2. 登录成功,认证中心会生成一个 token(有效期比较短)和一个 refreshToken(有效期比较长),返回给用户并保存在客户端。
  3. 用户访问系统 A,会在请求头中附带 token 信息,系统 A 可以自行进行验证 token
  4. 系统 A 验证通过,返回系统受保护的资源给客户端
  5. 当 token 过期了再请求系统 A 时,系统 A 验证不通过。用户可以使用 refreshToken 到认证中心换取新的 token,并更新保存在客户端。后续的请求使用新的 token 又可以正常访问系统了。
  6. 当 refreshtoken 过期了,可以重新登录或者做其他逻辑处理。

双 Token 模式提高了认证中心对用户的控制能力,因为每隔一段时间 token 失效后,用户需要到认证中心获取新 token。该模式弥补了 token 模式的缺点,又保持了 token 模式的优势。

3. 客户端对 cookie 或者 token 的保存

登录认证后认证中心返回的 cookie(或者 token),需要在客户端保存。

  • 如果系统 A、系统 B 和认证中心是在相同的主域名下,可以通过设置 set-cookie 中的 domain 为主域名,path 设置为根路径,实现后续对系统 A、B 的请求中请求头会自动携带 cookie 。因为设置域名将会使 cookie 对指定的域名及其所有子域名可用。
  • 如果系统 A、系统 B 不相同的主域名下,因为浏览器的同源策略,在不同源的请求中浏览器会限制 cookie 的发送,此时可以将 cookie 信息保存在 localStorage 中,以解决跨域请求 cookie 发送。

set-cookie:是响应标头,内容信息由服务器设置,响应返回,客户端保存。在客户端后续的请求中,根据登录响应头 set-cookie 的内容限制,决定后续请求头中是否要附带 cookie。set-cookie 中包含 cookie 内容,也包含 cookie 的其他信息,比如 Max-age(有效期)、domain(请求时 cookie 可以发送的域)、SameSite(跨站时携带 cookie 的约束)等。

4. JWT (JSON Web Token)

JWT 是一种特殊的 Token,由三个部分组成(header、payload、signature),中间用符号.连接

header 部分:由一个 JSON 对象,进行 base64 编码得到。
在这里插入图片描述

let header = {
  alg: "HS256", //签名使用的加密算法,HS256
  typ: "JWT", //一般是固定的
};
header = btoa(JSON.stringify(header)); //进行base64编码

payload 部分:主体内容部分,也是一个 JSON 对象,也要进行 base64 编码。
在这里插入图片描述

let payload = {
  name: "admin",
  age: 18,
};
payload = btoa(JSON.stringify(payload));

signature 部分:由前面 base64 编码得到的两个部分用.拼接,进行加密(需要一个秘钥),再进行 base64 编码得到。
在这里插入图片描述

token 是由服务器生成,返回给客户端并保存,在后续的请求中携带 token 进行请求。系统进行 token 验证时,解析出 token 中的 header 和 payload,用相同的秘钥进行加密处理后,再和 token 中的 signature 部分对比,如果相同则通过验证,不同则表示 token 被篡改了或者客户端没有进行登录伪造的。在单点登录模式二中,认证中心生成秘钥进行加密,可以将秘钥同步给系统 A、系统 B,这样系统 A、B 就可以自行验证 token 的有效性了。

5. 双 token 无感刷新

双 token 模式下 token 有效时间较短,refreshToken 的有效时间较长,当 token 失效后用 refreshToken 请求获取新的 token。当 refreshToken 也过期失效后,需要重新登录。

import axios from "axios";
//set将token和refreshtoken保存到localstorage
//get为从localstorage中取出token和refrestoken
import { getToken, setToken, getFreshToken, setFreshToken } from "./token.js";

const ins = axios.create({
  baseUrl: "http://localhost:3000",
  headers: {
    Authorization: `Bearer ${getToken()}`,
  },
});

//刷新token的请求
let promise;
function refreshToken() {
  if (promise) {
    return promise;
  }
  promise = new Promise(async (resolve) => {
    const resp = await ins.get("/refresh_token", {
      headers: {
        Authorization: `Bearer ${getFreshToken()}`,
      },
      __isRefreshToken: true,
    });
    if (resp.data.code === 200) {
      //刷新token成功
      resolve(true);
    } else {
      //刷新token失败,refreshToken也过期失效了
      resolve(false);
    }
  });
  promise.finally(() => {
    promise = null;
  });
  return promise;
}

//判断是否是刷新token的请求
function isRefreshRequest(config) {
  return !!config.__isRefreshToken;
}

ins.interceptors.response.use(async (res) => {
  if (res.headers.Authorization) {
    const token = res.headers.Authorization.replace("Bearer ", "");
    setToken(token);
    ins.defaults.headers.Authorization = `Bearer ${token}`;
  }
  if (res.headers.refreshtoken) {
    const freshtoken = res.headers.refreshtoken.replace("Bearer ", "");
    setFreshToken(freshtoken);
  }
  //无权限,且不是刷新token请求,是普通数据请求
  if (res.data.code === 401 && !isRefreshRequest(res.config)) {
    //刷新token
    const isSuccess = await refreshToken();
    if (isSuccess) {
      //刷新成功,重新请求
      res.config.headers.Authorization = `Bearer ${getToken()}`;
      const resp = await ins.request(res.config);
      return resp;
    } else {
      //刷新token失败,refreshToken过期了
      console.log("需要重新登录");
    }
  }
  return res.data;
});


export default ins;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值