🗣 Wd提问: 搭建授权服务器
🤖 Ai回答: 搭建简单的OAuth 2.0授权服务器
以下是一个使用Node.js和Express搭建的简单OAuth 2.0授权服务器的指南。这个示例适合学习和测试,不适用于生产环境(生产环境需要更多安全措施)。
1、环境准备
bash
安装Node.js (v14+)
确保已安装npm
创建项目目录
mkdir oauth-server && cd oauth-server
npm init -y
2、安装依赖
bash
npm install express oauth2-server express-session body-parser cors
3、项目结构
oauth-server/
├── server.js
└── package.json
4、编写授权服务器代码
server.js:
javascript
const express = require('express');
const oauthServer = require('oauth2-server');
const bodyParser = require('body-parser');
const cors = require('cors');
const session = require('express-session');
// 创建Express应用
const app = express();
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(session({ secret: 'your-secret-key', resave: false, saveUninitialized: true }));
// 模拟数据库 实际生产环境应使用数据库
const clients = {
'client1': {
clientId: 'client1',
clientSecret: 'secret1',
redirectUris: ['http://localhost:3000/callback'],
grants: ['authorization_code', 'password', 'refresh_token']
}
};
const users = {
'user1': {
id: 'user1',
username: 'user1',
password: 'password1' // 实际应用中应存储哈希密码
}
};
const tokens = {};
// 用于存储授权码
const authorizationCodes = {};
// OAuth 2.0 服务器配置
const oauth = new oauthServer({
model: {
// 获取客户端信息
getClient: function(clientId, clientSecret, callback) {
const client = clients[clientId];
if (!client (clientSecret && client.clientSecret !== clientSecret)) {
return callback(null, false);
}
return callback(null, client);
},
// 验证用户凭证
getUser: function(username, password, callback) {
const user = users[username];
if (!user user.password !== password) {
return callback(null, false);
}
return callback(null, user);
},
// 保存授权码
saveAuthorizationCode: function(code, client, user, callback) {
authorizationCodes[code] = {
code: code,
clientId: client.clientId,
userId: user.id,
redirectUri: client.redirectUris[0]
};
callback(null, code);
},
// 获取授权码
getAuthorizationCode: function(code, callback) {
const authCode = authorizationCodes[code];
if (!authCode) {
return callback(null, false);
}
callback(null, authCode);
},
// 删除授权码
revokeAuthorizationCode: function(code, callback) {
delete authorizationCodes[code];
callback(null, true);
},
// 生成访问令牌
generateAccessToken: function(client, user, scope, callback) {
const token = {
accessToken: Math.random().toString(36).substr(2, 15),
accessTokenExpiresAt: new Date(Date.now() + 3600 * 1000), // 1小时
refreshToken: Math.random().toString(36).substr(2, 15)
};
tokens[token.accessToken] = {
client: client,
user: user,
scope: scope,
token: token
};
callback(null, token.accessToken, token.accessTokenExpiresAt, token.refreshToken);
},
// 获取访问令牌
getAccessToken: function(accessToken, callback) {
const token = tokens[accessToken];
if (!token token.expiresAt < new Date()) {
return callback(null, false);
}
callback(null, token);
},
// 生成刷新令牌
generateRefreshToken: function(client, user, scope, callback) {
const refreshToken = Math.random().toString(36).substr(2, 15);
callback(null, refreshToken);
},
// 获取刷新令牌
getRefreshToken: function(refreshToken, callback) {
// 实际应用中应存储刷新令牌
callback(null, false);
},
// 刷新访问令牌
refreshAccessToken: function(client, refreshToken, scope, callback) {
// 实际应用中应验证刷新令牌
const newToken = {
accessToken: Math.random().toString(36).substr(2, 15),
accessTokenExpiresAt: new Date(Date.now() + 3600 * 1000),
refreshToken: Math.random().toString(36).substr(2, 15)
};
tokens[newToken.accessToken] = {
client: client,
user: { id: 'user1' }, // 实际应用中应获取用户
scope: scope,
token: newToken
};
callback(null, newToken.accessToken, newToken.accessTokenExpiresAt, newToken.refreshToken);
}
}
});
// 授权端点
app.post('/authorize', oauth.authorize(), (req, res) = {
// 授权成功,重定向到客户端回调URL
res.redirect(req.query.redirect_uri + '?code=' + req.oauth.code);
});
// 令牌端点
app.post('/token', oauth.token());
// 保护的API端点
app.get('/api/user', oauth.authorize(), (req, res) = {
res.json({ user: req.user.id, message: 'Protected data' });
});
// 启动服务器
const PORT = 3000;
app.listen(PORT, () = {
console.log(`Authorization Server running on port ${PORT}`);
});
5、启动服务器
bash
node server.js
6、测试授权流程
1、获取授权码
请求:
GET /authorize?response_type=code&client_id=client1&redirect_uri=http://localhost:3000/callback&scope=read
响应:
重定向到 `http://localhost:3000/callback?code=AUTHORIZATION_CODE`
2、获取访问令牌
请求:
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=AUTHORIZATION_CODE&client_id=client1&client_secret=secret1&redirect_uri=http://localhost:3000/callback
响应:
json
{
access_token: ACCESS_TOKEN,
token_type: Bearer,
expires_in: 3600,
refresh_token: REFRESH_TOKEN
}
3、访问受保护的API
请求:
GET /api/user
Authorization: Bearer ACCESS_TOKEN
响应:
json
{
user: user1,
message: Protected data
}
7、重要注意事项
1、生产环境安全:
使用HTTPS
使用安全的存储方式存储密码和令牌
添加CSRF保护
实现令牌刷新机制
添加速率限制
2、改进方向:
使用数据库存储客户端、用户和令牌
实现更复杂的授权流程
添加用户界面进行授权确认
实现更安全的随机数生成
3、学习资源:
[OAuth 2.0官方文档](https://oauth.net/2/)
[OAuth 2.0 for Developers](https://www.oauth.com/)
8、生产环境建议
对于生产环境,强烈建议使用成熟的授权服务器实现,如:
Auth0: 云服务
Keycloak: 开源身份和访问管理
ORY Hydra: 专注于OAuth 2.0和OpenID Connect的开源项目
这个示例仅用于理解OAuth 2.0基本工作原理,切勿直接用于生产环境。
希望这个指南对您有所帮助!如果您需要更详细的实现或特定功能的扩展,请告诉我。
📣 商家广告:





0
IP地址: 135.68.194.1
搜索次数: 0
提问时间: 2025-10-28 15:08:57
🛒 域名购买:
jamctr.com
zhong.tw
cdn.hk.cn
qz.gs
x-j.net
lw.biz
02.gs
wg.gs
03.gold
app.ln.cn
❓️ 热门提问:
ipv4的ip地址长度
服务器上装mysql
机柜的单位是台还是个
虚拟主机建站
lucene搜索引擎
云主机多少钱
cdn测试方法
怎么租用云服务器
关键词挖掘广告语词
pds机柜
豌豆Ai站群搜索引擎系统
🌐 域名评估:
vv.gs.cn
sf.zj.cn
xx.cn
v.qh.cn
krkn.cn
spacex.js.cn
tieba.cyou
ypph.cn
usfi.cn
skgi.cn
⛏ 最新挖掘:
凯里酸汤鱼
贵阳烤脑花
都匀毛尖茶
花溪牛肉粉
贵阳烤生蚝
贵阳烤豆腐
贵阳纸包鱼
贵阳特色菜
🖌 热门作画:
🤝 关于我们:
豌豆Ai
域名
建站
站群
留痕
推广
评估
源码
开发Ai
工具
日记
价格
加盟
广告
流量
留言
联系
🗨 加入群聊:
🔗 友情链接:
北京网站建设
Motor de búsqueda
ai提问
🧰 站长工具:
Ai工具 whois查询 搜索
📢 温馨提示:本站所有问答由Ai自动创作,内容仅供参考,若有误差请用“联系”里面信息通知我们人工修改或删除。
👉 技术支持:本站由豌豆Ai提供技术支持,使用的最新版:《豌豆Ai站群搜索引擎系统 V.25.10.25》搭建本站。