亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

JWT單點登錄入門教程:快速搭建安全的單點登錄系統

標簽:
安全 API
概述

JWT单点登录是一种高效的身份验证方式,通过JWT令牌实现用户一次登录即可访问多个系统,大幅提升用户体验和安全性。本文详细介绍了JWT的工作原理、优势及应用场景,并通过具体示例展示了如何使用JWT实现单点登录系统。

JWT简介
什么是JWT

JSON Web Tokens (JWT) 是一种开放标准 (RFC 7519),用于在两个信任方之间安全地传输信息。JWT 通常用于用户身份验证和信息交换,其主要特点是可以附带一组声明来表示用户的身份或权限。JWT 系统可以用于许多不同的上下文,包括但不限于 RESTful API,单点登录系统,以及移动应用的身份验证。

JWT 由三部分组成,这些部分通过点(.)分隔:

  1. 头部(Header):描述令牌的类型("JWT")和所使用的签名算法(例如:HMAC SHA256 或 RSA)。
  2. 载荷(Payload):包含声明(即,声明数据)。声明是键值对的形式,分为三类:预留的(例如:iss,代表Issuer,签发者)、公共的(例如:sub,代表Subject,主题)和私有的(由开发者自定义)。载荷会被签名,保证不可篡改。
  3. 签名(Signature):用于验证消息的完整性和签名者的身份。签名由头部、载荷以及签名算法和一个密钥计算而得。
JWT的工作原理

JWT 的工作原理如下:

  1. 当客户端请求访问需要身份验证的资源时,服务器需要确认客户端的身份。
  2. 服务器生成一个JWT并将其发送给客户端。
  3. 客户端保存JWT,通常在浏览器的Local Storage中或者HTTP头的Authorization字段中。
  4. 在每次请求需要验证身份的资源时,客户端都会发送JWT。
  5. 服务器接收到请求时,会解析JWT以验证其有效性(例如:签名、过期时间),然后根据载荷中的信息做出相应的处理。
JWT的优势和应用场景

JWT 的优势包括:

  • 状态无服务器:JWT 使后端可以无状态操作,不需要存储和查询Session。
  • 跨域支持:由于JWT是通过HTTPS协议通过Header传输的,所以跨域传输安全性较好。
  • 可拓展性:可以灵活添加自定义的claim。
  • 安全性:由于数据进行了加密签名,所以JWT在传输时不容易被篡改和伪造。

JWT的应用场景包括但不限于:

  • 单点登录(SSO)
  • 授权
  • 用户身份验证
单点登录的概念
什么是单点登录

单点登录(Single Sign-On,SSO)是一种身份验证方式,它允许用户使用一组凭证(通常是用户名和密码)登录一个系统,从而可以访问该系统中的所有资源以及它集成的其他系统。这意味着用户不再需要为每个独立系统单独登录,这不仅提高了用户体验,也简化了安全管理。

单点登录的优势

单点登录的主要优势包括:

  • 用户体验提升:用户只需要一次登录,就可以访问多个系统。
  • 减少管理成本:管理员只需要管理一个身份验证系统,减少了维护多个系统所带来的成本。
  • 增强安全性:集中式的身份验证系统可以采用更为严格的策略,提供更好的安全性。
常见的单点登录实现方式

常见的单点登录实现方式包括:

  • 基于Cookie的SSO:用户登录后,服务器将生成一个Session ID,存储在Cookie中,用户访问其他系统时通过共享Cookie中的Session ID来访问资源。
  • 基于Token的SSO:用户登录后,服务器根据用户信息生成一个Token,用户访问其他系统时将Token传递给相应的系统进行验证。
  • 基于OAuth和OpenID Connect:OAuth 2.0 和 OpenID Connect 提供了一种标准的方式来实现第三方应用的单点登录。
使用JWT实现单点登录的步骤
准备工作

创建项目环境

要开始使用JWT,首先需要创建一个开发环境。在这个例子中,我们将使用Node.js作为后端服务,前端可以使用任何你喜欢的框架(例如Vue.js或React)。

  • 创建一个新的Node.js项目
    mkdir jwt-sso
    cd jwt-sso
    npm init -y
  • 安装必要的库
    npm install express jsonwebtoken body-parser

安装必要的库

安装必要的库,包括Express(用于构建RESTful API)、jsonwebtoken(用于生成和验证JWT)和body-parser(用于解析HTTP请求体中的内容)。

npm install express jsonwebtoken body-parser
生成JWT令牌

生成JWT令牌的过程包括:

  1. 创建一个包含用户信息的载荷(Payload)。
  2. 使用一个密钥和签名算法为载荷生成签名。
  3. 将头部、载荷和签名组合成一个字符串。

示例如下:

const jwt = require('jsonwebtoken');

function generateToken(user) {
    const payload = { id: user.id, username: user.username }; // 用户信息
    const secret = 'mySecretKey'; // 用于签名的密钥
    const options = { expiresIn: '1h' }; // 设置有效期为1小时

    return jwt.sign(payload, secret, options);
}

const user = { id: 1, username: 'john_doe' };
const token = generateToken(user);
console.log(token); // 输出生成的JWT令牌
令牌验证和解析

验证和解析JWT令牌的过程包括:

  1. 从请求头或其他地方获取JWT令牌。
  2. 使用相同的密钥和签名算法验证令牌。
  3. 解析载荷获取用户信息。

示例如下:

function verifyToken(req, res, next) {
    const token = req.headers.authorization && req.headers.authorization.split(' ')[1]; // 从Authorization头获取JWT
    const secret = 'mySecretKey'; // 用于签名的密钥

    if (token) {
        jwt.verify(token, secret, (err, decoded) => {
            if (err) {
                return res.status(401).send({ message: 'Unauthorized' }); // 如果验证失败,返回401未授权
            }
            req.user = decoded; // 如果验证成功,将用户信息保存在请求对象中
            next(); // 继续处理下一个中间件或路由
        });
    } else {
        return res.status(401).send({ message: 'Unauthorized' });
    }
}
实现登录和认证流程

实现登录和认证流程包括:

  1. 用户通过登录界面提交用户名和密码。
  2. 服务器验证用户信息,并生成一个JWT令牌。
  3. 将JWT令牌返回给用户。
  4. 用户使用JWT令牌访问需要认证的资源。

示例如下:

const express = require('express');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.json());

const users = [
    { id: 1, username: 'john_doe', password: 'password123' }
];

app.post('/login', (req, res) => {
    const { username, password } = req.body;
    const user = users.find(u => u.username === username && u.password === password);

    if (user) {
        const token = generateToken(user);
        res.json({ token });
    } else {
        res.status(401).send({ message: 'Invalid credentials' });
    }
});

app.use(verifyToken);

app.get('/profile', (req, res) => {
    res.json({ user: req.user });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
配置HTTPS

为了确保JWT令牌的安全传输,推荐使用HTTPS。以下是如何配置HTTPS的示例:

const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();

const options = {
    key: fs.readFileSync('/path/to/ssl/privatekey.pem'),
    cert: fs.readFileSync('/path/to/ssl/cert.pem')
};

const server = https.createServer(options, app);
前端调用后端API

前端可以通过Fetch API来调用后端API,实现JWT令牌的获取和验证。以下是一个简例:

async function fetchToken() {
    const response = await fetch('/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ username: 'john_doe', password: 'password123' })
    });
    const data = await response.json();
    console.log(data.token);
}
JWT单点登录的安全性
令牌的安全传输

安全传输JWT令牌非常重要,必须确保令牌不被拦截或篡改。推荐使用HTTPS(HTTP over SSL/TLS)来加密传输过程,以确保令牌在传输过程中是安全的。此外,令牌应当通过HTTP请求头中的Authorization字段传输,而不是通过查询字符串或URL参数。

令牌的签名和加密

JWT 令牌通过签名来保证其完整性。签名算法(如HMAC、RSA等)保证令牌没有被篡改。同时,应该使用密钥来签名,这个密钥必须严格保密。

示例如下:

const jwt = require('jsonwebtoken');
const secret = 'mySecretKey';

const token = jwt.sign({ id: 1, username: 'john_doe' }, secret, { expiresIn: '1h' });
console.log(token);
令牌的有效期和刷新机制

为确保安全性,JWT 令牌通常会被设置一个较短的有效期。当令牌即将过期时,客户端可以通过访问刷新端点来获取一个新的令牌。刷新端点需要存储一个长期有效的刷新令牌,并在每次刷新请求时验证刷新令牌。

示例如下:

app.post('/refresh', (req, res) => {
    const refreshToken = req.body.refresh_token;
    const secret = 'myRefreshSecretKey';

    jwt.verify(refreshToken, secret, (err, decoded) => {
        if (err) {
            return res.status(401).send({ message: 'Unauthorized' });
        }

        const user = { id: decoded.id, username: decoded.username };
        const newToken = generateToken(user);
        res.json({ token: newToken });
    });
});
实际案例解析
示例代码展示

我们将在前面说明的基础上,展示一个完整的JWT单点登录系统。这个系统包括以下部分:

  • 用户登录接口:用户提供用户名和密码,系统验证用户身份并返回JWT令牌。
  • 保护的资源接口:需要JWT令牌验证用户身份。
  • 刷新令牌接口:用户凭长期有效的刷新令牌获取新的JWT令牌。
const express = require('express');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.json());

const users = [
    { id: 1, username: 'john_doe', password: 'password123' }
];

const SECRET = 'mySecretKey';
const REFRESH_SECRET = 'myRefreshSecretKey';

function generateToken(user) {
    const payload = { id: user.id, username: user.username };
    return jwt.sign(payload, SECRET, { expiresIn: '1h' });
}

function verifyToken(req, res, next) {
    const token = req.headers.authorization && req.headers.authorization.split(' ')[1];
    if (token) {
        jwt.verify(token, SECRET, (err, decoded) => {
            if (err) {
                return res.status(401).send({ message: 'Unauthorized' });
            }
            req.user = decoded;
            next();
        });
    } else {
        res.status(401).send({ message: 'Unauthorized' });
    }
}

app.post('/login', (req, res) => {
    const { username, password } = req.body;
    const user = users.find(u => u.username === username && u.password === password);
    if (user) {
        const token = generateToken(user);
        res.json({ token });
    } else {
        res.status(401).send({ message: 'Invalid credentials' });
    }
});

app.use(verifyToken);

app.get('/profile', (req, res) => {
    res.json({ user: req.user });
});

app.post('/refresh', (req, res) => {
    const refreshToken = req.body.refresh_token;
    jwt.verify(refreshToken, REFRESH_SECRET, (err, decoded) => {
        if (err) {
            return res.status(401).send({ message: 'Unauthorized' });
        }

        const user = { id: decoded.id, username: decoded.username };
        const newToken = generateToken(user);
        res.json({ token: newToken });
    });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
部署和测试

部署和测试步骤如下:

  1. 将代码部署到服务器。
  2. 使用前端框架(如Vue.js或React)创建一个用户界面,用于登录和访问受保护资源。
  3. 在登录后,前端应用将保存JWT令牌,并在访问受保护资源时,将其放在HTTP请求头中。
  4. 使用工具如Postman来测试API,确保登录、刷新令牌等功能正常工作。
常见问题及解决方案

问题1:JWT令牌失效

原因:如果没有正确设置JWT令牌的有效期或刷新机制,令牌可能会在用户使用过程中失效。

解决方案:设置一个较短的有效期(如1小时),并在令牌即将失效时提供一个刷新令牌接口,让用户能够获取新的JWT令牌。

问题2:JWT令牌被盗用

原因:如果JWT令牌通过不安全的渠道传输(如HTTP而非HTTPS),可能会被拦截。

解决方案:确保通过HTTPS传输JWT令牌,并且在HTTP请求头中携带令牌(例如:Authorization: Bearer jwt-token)。

问题3:JWT的被篡改

原因:如果签名算法或密钥管理不当,JWT令牌可能会被篡改。

解决方案:使用强加密算法(如HS256)和复杂密钥来签名JWT令牌。

总结与后续学习方向
总结JWT单点登录的优势和注意事项

JWT 单点登录提供了无状态、跨域支持、可拓展性和安全性等优势。然而,在实现时需要注意:

  • 使用HTTPS来保护令牌传输的安全性。
  • 令牌的签名应当使用强加密算法和复杂的密钥。
  • 令牌的有效期应当合理设置,并提供刷新机制。
  • 通过适当的中间件和验证逻辑,确保令牌的安全性。
推荐进一步学习的资源
  • 在线课程:可以在慕课网找到关于JWT和单点登录的相关课程。
  • 文档和教程:官方文档和一些技术博客(如Medium)提供了详细的JWT使用教程。
  • 实战项目:尝试构建一些实战项目,例如实现一个简单的用户管理系统,来加深对JWT的理解。
點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消