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

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

JWT單點登錄學習:從入門到實踐教程

標簽:
PHP Java 安全
概述

本文详细介绍了JWT单点登录的基本概念、工作原理以及组成部分,并通过实例演示了如何使用JWT实现单点登录的步骤,包括用户认证、生成JWT、服务端验证和客户端存储发送,以及常见问题的解决方案。

JWT简介与概念

什么是JWT

JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息。该信息是通过数字签名进行加密的,因此可以防止数据被篡改或伪造。JWT主要由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。通过这种方式,JWT可以在不依赖服务器状态的情况下验证用户身份,从而实现无状态的认证机制。

JWT的工作原理

JWT的工作原理可以分为三个步骤:

  1. 生成JWT:客户端向服务器发送用户名和密码,服务器验证用户信息后生成一个JWT,并将其发回给客户端。
  2. 存储JWT:客户端接收到JWT后,通常会将其存储在浏览器的LocalStorageSessionStorage中,也可以存储在Cookie中。
  3. 发送JWT:当客户端访问受保护的资源时,它会将JWT作为请求的头部信息发送给服务器。服务器验证JWT的签名和内容,确认用户身份。

JWT的组成部分

  • Header(头部):头部通常包含两个部分:令牌类型(例如JWT)以及算法(例如HMAC SHA256或RSA)。
  • Payload(载荷):载荷携带了声明(payload claims),声明是JSON对象,包含诸如用户ID(sub)、用户名(username)等信息。需要注意的是,载荷并不进行签名,所以在传输过程中不能携带敏感信息。
  • Signature(签名):签名用于验证消息发送者的真实性以及消息完整性。签名是通过使用Header中指定的算法,将头部和载荷进行Base64编码后,与一个密钥一起哈希得到的。

示例代码

下面以一个简单的Python示例来生成JWT:

import jwt
import datetime

# 定义payload
payload = {
    'sub': '1234567890',
    'name': 'John Doe',
    'iat': datetime.datetime.utcnow(),
    'exp': datetime.datetime.utcnow() + datetime.timedelta(days=30)
}

# 生成JWT,使用密钥进行签名
jwt_token = jwt.encode(payload, 'secret', algorithm='HS256')

print(jwt_token)
单点登录(SSO)基础

单点登录的概念

单点登录(Single Sign-On,SSO)是一种身份验证机制,允许用户使用一组凭证(用户名和密码)登录多个系统。SSO通过一个中心化的身份验证服务,用户只需要一次登录操作就可以访问多个相关的系统。这种方式可以简化用户管理,提高用户体验。

SSO的优势与应用场景

  • 用户体验:用户只需进行一次登录操作,后续访问相关系统时无需再次输入用户名和密码。
  • 安全性:主要的身份验证信息存放在中心化的服务器上,降低了密码泄露的风险。
  • 管理成本:集中管理用户信息,减少了维护多套认证系统的成本。
  • 应用范围:广泛应用于企业内部系统集成、云服务提供商以及多应用平台集成等场景。

示例代码

以下是一个简单的SSO集成示例,演示了如何使用JWT实现单点登录:

const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');

const app = express();
const users = [
    { id: '1', username: 'user1', password: bcrypt.hashSync('password123', 8) }
];

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

    const user = users.find(u => u.username === username);

    if (!user) {
        return res.status(400).json({ message: 'User not found' });
    }

    if (!bcrypt.compareSync(password, user.password)) {
        return res.status(400).json({ message: 'Invalid password' });
    }

    const token = jwt.sign({ id: user.id, username: user.username }, 'secretKey', { expiresIn: '1h' });

    res.json({ token });
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});
JWT实现单点登录的步骤

准备工作:环境搭建与依赖库安装

为了实现JWT单点登录,你需要先搭建好开发环境,并安装必要的依赖库。下面以Node.js与Express框架为例,介绍环境搭建步骤:

  1. 安装Node.js:确保你的计算机上安装了最新版本的Node.js。
  2. 创建项目文件夹:在命令行中输入mkdir jwt-sso,然后进入该文件夹。
  3. 初始化项目:运行npm init,按照提示完成项目初始化。
  4. 安装依赖库:使用npm install express express-jwt jsonwebtoken bcryptjs命令安装Express、express-jwt(用于验证JWT)、jsonwebtoken(用于生成JWT)和bcryptjs(用于加密密码)。

发放JWT:用户认证与生成JWT

在用户登录时,需要进行用户身份验证并生成JWT。下面提供一个简单的登录后端代码示例:

const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');

const app = express();
const users = [
    { id: '1', username: 'user1', password: bcrypt.hashSync('password123', 8) }
];

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

    const user = users.find(u => u.username === username);

    if (!user) {
        return res.status(400).json({ message: 'User not found' });
    }

    if (!bcrypt.compareSync(password, user.password)) {
        return res.status(400).json({ message: 'Invalid password' });
    }

    const token = jwt.sign({ id: user.id, username: user.username }, 'secretKey', { expiresIn: '1h' });

    res.json({ token });
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

验证JWT:服务端验证、客户端存储与发送

在前端,用户登录成功后,可以将JWT存储于LocalStorageCookie中。下面提供一个使用LocalStorage存储JWT的简单示例:

fetch('/login', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({ username: 'user1', password: 'password123' })
})
.then(response => response.json())
.then(data => {
    localStorage.setItem('token', data.token);
});
``

在每次请求受保护资源时,客户端需要将JWT作为请求头中的`Authorization`字段发送给服务器。下面提供一个使用JWT发送请求的示例:

```javascript
const token = localStorage.getItem('token');

fetch('/protected-resource', {
    headers: {
        'Authorization': `Bearer ${token}`
    }
})
.then(response => response.json())
.then(data => console.log(data));

服务端可以使用express-jwt中间件来验证JWT,确保请求合法。下面提供一个验证JWT的示例:

const jwt = require('express-jwt'); // 引入express-jwt中间件

// 验证JWT
app.use(jwt({
    secret: 'secretKey', // 密钥必须与生成JWT时使用的密钥保持一致
    algorithms: ['HS256'] // 指定算法
}).unless({ path: [ '/login' ] })); // 登录请求不需要JWT验证

// 受保护的资源
app.get('/protected-resource', (req, res) => {
    res.json({ message: 'This is a protected resource' });
});
实践案例:使用Node.js实现JWT单点登录

后端代码实现

以下是一个简单的后端示例,它提供了用户注册、登录和获取用户信息的功能:

const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');

const app = express();
const users = [];

// 用户注册
app.post('/register', (req, res) => {
    const { username, password } = req.body;

    const existingUser = users.find(u => u.username === username);
    if (existingUser) {
        return res.status(400).json({ message: 'User already exists' });
    }

    const hash = bcrypt.hashSync(password, 8);

    users.push({ id: users.length + 1, username, password: hash });

    res.json({ message: 'User registered successfully' });
});

// 用户登录
app.post('/login', (req, res) => {
    const { username, password } = req.body;

    const user = users.find(u => u.username === username);

    if (!user) {
        return res.status(400).json({ message: 'User not found' });
    }

    if (!bcrypt.compareSync(password, user.password)) {
        return res.status(400).json({ message: 'Invalid password' });
    }

    const token = jwt.sign({ id: user.id, username: user.username }, 'secretKey', { expiresIn: '1h' });

    res.json({ token });
});

// 获取用户信息
app.get('/me', (req, res) => {
    const authHeader = req.headers.authorization;
    if (!authHeader) {
        return res.status(401).json({ message: 'No token provided' });
    }

    const parts = authHeader.split(' ');
    if (parts.length !== 2) {
        return res.status(401).json({ message: 'Token not valid' });
    }

    const [scheme, token] = parts;

    if (!/^Bearer$/i.test(scheme)) {
        return res.status(401).json({ message: 'Token not valid' });
    }

    jwt.verify(token, 'secretKey', (err, decoded) => {
        if (err) {
            return res.status(401).json({ message: 'Token not valid' });
        }

        const user = users.find(u => u.id === decoded.id);
        if (!user) {
            return res.status(401).json({ message: 'User not found' });
        }

        res.json({ id: user.id, username: user.username });
    });
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

前端代码实现

前端可以使用JavaScript或任何前端框架(如React、Vue等)来实现用户界面。这里提供一个简单的前端示例,使用JavaScript和Fetch API进行HTTP请求:

document.getElementById('register').addEventListener('click', () => {
    const username = document.getElementById('username').value;
    const password = document.getElementById('password').value;

    fetch('/register', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ username, password })
    })
    .then(response => response.json())
    .then(data => console.log(data));
});

document.getElementById('login').addEventListener('click', () => {
    const username = document.getElementById('username').value;
    const password = document.getElementById('password').value;

    fetch('/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ username, password })
    })
    .then(response => response.json())
    .then(data => {
        localStorage.setItem('token', data.token);
        console.log('Token:', data.token);
    });
});

document.getElementById('getProfile').addEventListener('click', () => {
    const token = localStorage.getItem('token');

    fetch('/me', {
        headers: {
            'Authorization': `Bearer ${token}`
        }
    })
    .then(response => response.json())
    .then(data => console.log(data));
});

完整流程演示

  1. 用户在前端界面输入用户名和密码,点击注册按钮。
  2. 后端接收请求,验证用户名和密码,并将新用户信息存储到模拟数据库中。
  3. 用户在前端界面输入用户名和密码,点击登录按钮。
  4. 后端接收请求,验证用户信息,生成JWT并返回给前端。
  5. 前端接收到JWT后将其存储在LocalStorage中。
  6. 用户点击获取用户信息按钮,前端将JWT添加到请求头中发送请求。
  7. 后端验证JWT有效性并返回用户信息。
常见问题与解决方案

JWT过期时间设置与刷新

JWT支持设置过期时间(exp),当JWT过期后需要重新登录。为了提高用户体验,可以实现JWT刷新机制,即在JWT即将过期时自动获取新的JWT。

在生成JWT时可以设置较长的过期时间,例如12小时:

const token = jwt.sign({ id: user.id, username: user.username }, 'secretKey', { expiresIn: '12h' });

可以通过设置refreshToken来实现JWT刷新功能,当JWT即将过期时获取新的JWT:

const refreshToken = jwt.sign({ id: user.id, username: user.username }, 'refreshSecretKey', { expiresIn: '30d' });

fetch('/refresh', {
    headers: {
        'Authorization': `Bearer ${token}`
    }
})
.then(response => response.json())
.then(data => {
    localStorage.setItem('token', data.newToken);
});

安全性最佳实践

  • 密钥管理:使用强密钥,并定期更换密钥以增强安全性。
  • HTTPS:确保所有请求都是通过HTTPS传输的,以保护JWT不被拦截。
  • 访问控制:根据业务需求,限制JWT的使用范围,避免JWT被滥用。
  • JWT签名验证:始终在服务器端验证JWT的签名和内容,防止篡改。
  • 存储安全:妥善存储JWT,避免存储在客户端的Cookie中。

错误调试与排查

  • 检查密钥:确保生成JWT和验证JWT时使用相同的密钥。
  • 检查过期时间:确认JWT的过期时间是否设置合理,过期后请刷新JWT。
  • 调试工具:使用浏览器的开发工具或Postman等工具进行调试,查看请求和响应的具体内容。
  • 日志记录:记录重要的操作日志,便于追踪问题。
总结与进一步学习资源

主要知识点回顾

本文介绍了JWT的基本概念、单点登录(SSO)的原理以及如何使用JWT实现SSO。通过实例演示了JWT的生成、存储和验证过程。解释了JWT过期时间的设置、刷新机制、安全性最佳实践和错误调试方法。

可参考的学习资料与项目

  • 慕课网:提供了丰富的在线课程资源,涵盖从入门到高级的各种编程课程。例如,可以学习《JWT实现单点登录》和《Node.js开发实战》等课程。
  • 官方文档:官方文档是学习JWT和Express的最佳资源,提供了详细的技术参数和示例代码。例如,可以查阅jsonwebtokenexpress-jwt的官方文档。
  • 社区讨论:可以访问Stack Overflow等技术论坛,寻找有关JWT和SSO的讨论和解决方案。

通过上述内容,您可以更加深入地了解并实践JWT单点登录技术。

點擊查看更多內容
TA 點贊

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

評論

作者其他優質文章

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

100積分直接送

付費專欄免費學

大額優惠券免費領

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

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

幫助反饋 APP下載

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

公眾號

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

舉報

0/150
提交
取消