const express = require('express');
const session = require('express-session');
const passport = require('passport');
const OAuth2Strategy = require('passport-oauth2');
const app = express();
// 配置 Session
app.use(session({
secret: 'your-secret-key',
resave: false,
saveUninitialized: false,
cookie: { secure: false } // 生产环境请设置为 true
}));
app.use(passport.initialize());
app.use(passport.session());
// 配置 NodeLoc OAuth2 策略
passport.use('NodeLoc', new OAuth2Strategy({
authorizationURL: `${process.env.NodeLoc_URL}/oauth-provider/authorize`,
tokenURL: `${process.env.NodeLoc_URL}/oauth-provider/token`,
clientID: process.env.NodeLoc_CLIENT_ID,
clientSecret: process.env.NodeLoc_CLIENT_SECRET,
callbackURL: process.env.NodeLoc_REDIRECT_URI,
scope: ['openid', 'profile', 'email']
},
async (accessToken, refreshToken, profile, done) => {
try {
// 获取用户信息
const response = await fetch(
`${process.env.NodeLoc_URL}/oauth-provider/userinfo`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
const user = await response.json();
// 将 access_token 保存到用户对象
user.accessToken = accessToken;
user.refreshToken = refreshToken;
return done(null, user);
} catch (error) {
return done(error);
}
}
));
// 序列化和反序列化用户
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
// 路由
// 首页 - 显示登录状态
app.get('/', (req, res) => {
if (req.isAuthenticated()) {
res.send(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>欢迎</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px;
}
.user-card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
background: #f9f9f9;
}
.avatar {
width: 80px;
height: 80px;
border-radius: 50%;
}
.logout-btn {
background: #dc3545;
color: white;
padding: 10px 20px;
text-decoration: none;
border-radius: 4px;
display: inline-block;
margin-top: 15px;
}
</style>
</head>
<body>
<div class="user-card">
<h1>欢迎,${req.user.name}!</h1>
<img src="${req.user.avatar_url}" alt="Avatar" class="avatar" />
<p><strong>用户名:</strong> ${req.user.username}</p>
<p><strong>用户 ID:</strong> ${req.user.id}</p>
<p><strong>信任等级:</strong> ${req.user.trust_level}</p>
<a href="/logout" class="logout-btn">退出登录</a>
</div>
</body>
</html>
`);
} else {
res.send(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>登录</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.login-btn {
background: #0088cc;
color: white;
padding: 15px 30px;
text-decoration: none;
border-radius: 4px;
font-size: 18px;
}
.login-btn:hover {
background: #006699;
}
</style>
</head>
<body>
<a href="/auth/NodeLoc" class="login-btn">使用 NodeLoc 登录</a>
</body>
</html>
`);
}
});
// 发起授权
app.get('/auth/NodeLoc', passport.authenticate('NodeLoc'));
// 授权回调
app.get('/auth/callback',
passport.authenticate('NodeLoc', { failureRedirect: '/login' }),
(req, res) => {
// 登录成功,重定向到首页
res.redirect('/');
}
);
// 退出登录
app.get('/logout', (req, res) => {
req.logout((err) => {
if (err) {
return res.redirect('/');
}
res.redirect('/');
});
});
// API 示例 - 获取当前用户
app.get('/api/me', (req, res) => {
if (!req.isAuthenticated()) {
return res.status(401).json({ error: 'Not authenticated' });
}
res.json({
id: req.user.id,
username: req.user.username,
name: req.user.name,
avatar_url: req.user.avatar_url,
trust_level: req.user.trust_level
});
});
// 启动服务器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
console.log(`请确保设置了以下环境变量:`);
console.log(` - NodeLoc_URL`);
console.log(` - NodeLoc_CLIENT_ID`);
console.log(` - NodeLoc_CLIENT_SECRET`);
console.log(` - NodeLoc_REDIRECT_URI`);
});