sso单点登录

3 篇文章 0 订阅

单点登录(Single Sign-On,简称SSO)是一种身份认证和访问控制的机制,允许用户使用一组凭据(如用户名和密码)登录后,其它多个系统项目可直接访问。

单点登录的优点:

  1. 用户只需登录一次,即可访问多个应用程序,提供了更好的用户体验和便利性。
  2. 通过集中的身份验证,可以减少密码泄露和密码管理问题。此外,SSO还可以与其他身份验证机制(如多因素身份验证)结合使用,提供更强的安全性。
  3. SSO可以减少管理员的工作量,因为他们不需要为每个应用程序单独管理用户凭据和权限。

完整代码已上传github:https://github.com/benxiaohaihuiwan/SingleSignOn

需要安装的插件

npm i express 启动服务编写接口
npm i express-session  操作cookie
npm i jsonwebtoken  生成token
npm i cors 解决跨域

需要建立A项目,B项目,server项目,来验证单点登录效果。A,B项目可以直接使用 npm init vite 建立项目,这里我建立的都是vue项目。根目录下建sso.html,A,B项目统一用的登录页面

  • 首先说server项目,建一个index.js文件,顺便安装上述说的四个插件。
import express from "express";
import session from "express-session";
import fs from "node:fs";
import cors from "cors";
import jwt from "jsonwebtoken";

const appToMapUrl = {
  // A 项目的 appId
  as6s2ipA: {
    url: "http://localhost:5188",
    name: "vue",
    secretKey: "%Y&*VGHJKLsjkas",
    token: "",
  },
  // B 项目的 appId
  bs789ipB: {
    url: "http://localhost:5189",
    secretKey: "%Y&*FRTYGUHJIOKL",
    name: "react",
    token: "",
  },
};

// 搭建服务
const app = express();

// 解析客户端发送的数据
app.use(express.json());

// 解决跨域
app.use(cors());

// 生成一个 cookie
app.use(
  session({
    secret: "$%^&*()_+DFGHJKL",
    cookie: {
      maxAge: 1000 * 60 * 60 * 24 * 7, //过期时间
    },
  })
);

// 生成token
const getToken = (appId) => {
  /**
   * 1 第一个参数就是荷载,存我们的信息
   * 2 第二个参数是一个密钥,记录在服务器中,在验证时需要用到此参数
   * 3 第三个参数通常是从redis取,设置过期时间,在这里先不设置
   */
  return jwt.sign({ appId }, appToMapUrl[appId].secretKey);
};
/**
 * 一进到页面,就调用登录接口
 * 1 登录过,就返回一个token
 * 2 没登录过,则跳转到登录页面
 */
app.get("/login", (req, res) => {
  const appId = req.query.appId;
  const url = appToMapUrl[appId].url
  if (req.session.username) {
    // 若是有值,证明登录过
    let token;
    if (appToMapUrl[appId].token) {
      // 第一个项目访问
      token = appToMapUrl[appId].token;
    } else {
      // 后面项目访问
      token = getToken(appId);

      appToMapUrl[appId].token = token;
    }
    // 如果 登录过 则 重定向
    res.redirect(`${url}?token=${token}`);
    return;
  }
  const html = fs.readFileSync("../sso.html", "utf-8");

  res.send(html);
});

// 登录成功接口
app.get("/loginSuccess", (req, res) => {
  const { username, password, appId } = req.query;
  // 实际情况下,需要在判断下账号密码是否对应。

  // 生成响应的token
  const token = getToken(appId);
  appToMapUrl[appId].token = token; // 存一份token值
  req.session.username = username; // 存一个标识证明登录过
  const url = appToMapUrl[appId].url; // 获取 url
  // 登录后,重定向页面
  res.redirect(`${url}?token=${token}`);
  //   console.log(username, password, appId);

  res.send("ok");
});

// 服务
app.listen(3000, () => {
  console.log("启动一个3000的服务");
});


  • sso.html 登录页面,进行登录
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    登录页面
    <form action="/loginSuccess" method="get">
      <label for="username">
        账号:<input name="username" id="username" type="text" />
      </label>
      <label for="password"
        >密码:<input name="password" id="password" type="password"
      /></label>
      <!-- 隐藏appId 作为参数传递 登录的时候 -->
      <label for="appId"
        ><input name="appId" value="" id="appId" type="hidden"
      /></label>
      <button type="submit" id="button">登录</button>
    </form>
    <script>
      // 获取 appId 的参数,提交表单时候要传递
      const appId = location.search.split("=")[1];
      document.getElementById("appId").value = appId;
    </script>
  </body>
</html>

  • A项目 App.vue
<script setup lang="ts">
// 获取token值
const token = location.search.split("=")[1];

// 若是没有 token,则才调用登录接口
if (!token) {
  // 调用登录接口,跳转页面 传递appId 让用户知道是从那个项目上跳转, 数值需要与appToMapUrl对应
  fetch("http://localhost:3000/login?appId=as6s2ipA").then((res) => {
    location.href = res.url;
  });
}
// else {
//   // 存储下 token
//   localStorage.setItem("token", token);
// }
</script>

<template>
  <div>项目A页面</div>
</template>

  • B项目 App.vue
<script setup>
// 获取token值
const token = location.search.split("=")[1];

// 若是没有 token,则才调用登录接口
if (!token) {
  // 调用登录接口,跳转页面 传递appId 让用户知道是从那个项目上跳转的,, 数值需要与appToMapUrl对应
  fetch("http://localhost:3000/login?appId=bs789ipB").then((res) => {
    location.href = res.url;
  });
}
// else {
//   // 存储下 token
//   localStorage.setItem("token", token);
// }
</script>

<template>
  <div>项目B页面</div>
</template>

  • 26
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值