5分钟学会实现单点登录

179 阅读3分钟

什么是单点登录?

单点登录(Single Sign-On,SSO)是一个允许用户使用一个集中的身份验证系统访问多个应用程序的机制。这在前端开发中是一个重要的课题,因为它能够简化用户的登录体验,并提高安全性。

为什么需要单点登录?

  • 提高用户体验:用户只需要登录一次,就可以访问多个应用程序,避免了频繁输入用户名和密码的麻烦。

  • 提高安全性:通过集中管理认证信息,可以更好地控制和保护用户数据。

  • 简化管理:系统管理员可以更方便地管理用户权限和访问控制。

前端实现单点登录的常见方法

  • OAuth 2.0

    • OAuth 2.0 是一种开放标准,用于访问用户资源的授权。
    • 常用于第三方登录,例如使用 Google、Facebook 等账户登录第三方应用。
    • 流程通常包括获取授权码、使用授权码换取访问令牌、使用访问令牌访问资源。
  • SAML

    • 安全断言标记语言(Security Assertion Markup Language, SAML)是一种用于实现 SSO 的 XML 标准。
    • 常用于企业内部系统之间的单点登录。
    • 流程通常包括身份提供者(IdP)和服务提供者(SP)之间的信任关系建立、用户认证、断言传递等。
  • JWT(JSON Web Token)

    • JWT 是一种紧凑的、URL 安全的令牌格式,用于在各方之间传递经过签名的 JSON 对象。
    • 常用于现代 Web 应用中的身份验证和授权。
    • 流程通常包括生成 JWT、前端存储 JWT、每次请求时携带 JWT 进行验证。

实现方法:OAuth 2.0 和 JWT 实现单点登录

  • OAuth 2.0 流程

    • 用户点击“登录”按钮,前端跳转到授权服务器。
    • 用户在授权服务器上进行认证并同意授权。
    • 授权服务器返回授权码给前端。
    • 前端将授权码发送给后端,后端用授权码换取访问令牌。
    • 后端将访问令牌返回给前端,前端使用该令牌访问资源。
  • JWT 流程

    • 用户登录时,后端生成一个 JWT 并返回给前端。
    • 前端将 JWT 存储在本地存储或 Cookie 中。
    • 每次发送请求时,前端在请求头中携带 JWT。
    • 后端验证 JWT 的有效性,并根据其中的信息进行授权。

项目示例代码

假设我们使用 React 作为前端框架,Node.js 和 Express 作为后端框架,演示一个简单的 JWT 单点登录实现。

import React, { useState } from 'react';
import axios from 'axios';

function App() {
  const [token, setToken] = useState('');

  const handleLogin = async () => {
    const response = await axios.post('http://localhost:4000/login', {
      username: 'user',
      password: 'password',
    });
    setToken(response.data.token);
  };

  const handleGetData = async () => {
    const response = await axios.get('http://localhost:4000/data', {
      headers: {
        Authorization: `Bearer ${token}`,
      },
    });
    console.log(response.data);
  };

  return (
    <div>
      <button onClick={handleLogin}>Login</button>
      <button onClick={handleGetData}>Get Data</button>
    </div>
  );
}

export default App;

后端

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

app.use(express.json());

const SECRET_KEY = 'your_secret_key';

app.post('/login', (req, res) => {
  const { username, password } = req.body;
  // 假设用户名和密码验证成功
  const token = jwt.sign({ username }, SECRET_KEY, { expiresIn: '1h' });
  res.json({ token });
});

app.get('/data', (req, res) => {
  const authHeader = req.headers.authorization;
  const token = authHeader && authHeader.split(' ')[1];
  if (!token) return res.sendStatus(401);

  jwt.verify(token, SECRET_KEY, (err, user) => {
    if (err) return res.sendStatus(403);
    res.json({ data: 'Protected Data' });
  });
});

app.listen(4000, () => {
  console.log('Server is running on http://localhost:4000');
});

借助第三方库

借助第三方库的话是个很好的选择,我们可以在github上搜索到很多这种库,推荐一个小型轻便的 universal-cookie 库,可以在项目中很简单的实现单点登录

原理也很简单

  • 用户点击登录按钮,前端发送登录请求到后端。

  • 后端验证用户名和密码,并生成 JWT,返回给前端。

  • 前端将 JWT 存储在 Cookie 中。

  • 用户每次访问受保护的资源时,前端从 Cookie 中读取 JWT,并在请求头中携带 JWT 进行验证。

  • 后端验证 JWT 的有效性,并返回相应的数据。

使用 universal-cookie 库可以简化前端对 Cookie 的管理,从而实现单点登录