mirror of
https://github.com/songquanpeng/one-api.git
synced 2025-11-12 19:33:41 +08:00
feat: add Discord Oauth2 support (1)
This commit is contained in:
@@ -12,6 +12,7 @@ import AddUser from './pages/User/AddUser';
|
||||
import { API, getLogo, getSystemName, showError, showNotice } from './helpers';
|
||||
import PasswordResetForm from './components/PasswordResetForm';
|
||||
import GitHubOAuth from './components/GitHubOAuth';
|
||||
import DiscordOAuth from './components/DiscordOAuth';
|
||||
import PasswordResetConfirm from './components/PasswordResetConfirm';
|
||||
import { UserContext } from './context/User';
|
||||
import { StatusContext } from './context/Status';
|
||||
@@ -230,6 +231,14 @@ function App() {
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path='/oauth/discord'
|
||||
element={
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<DiscordOAuth />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path='/setting'
|
||||
element={
|
||||
@@ -243,11 +252,11 @@ function App() {
|
||||
<Route
|
||||
path='/topup'
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<TopUp />
|
||||
</Suspense>
|
||||
</PrivateRoute>
|
||||
<PrivateRoute>
|
||||
<Suspense fallback={<Loading></Loading>}>
|
||||
<TopUp />
|
||||
</Suspense>
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
|
||||
57
web/src/components/DiscordOAuth.js
Normal file
57
web/src/components/DiscordOAuth.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { Dimmer, Loader, Segment } from 'semantic-ui-react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { API, showError, showSuccess } from '../helpers';
|
||||
import { UserContext } from '../context/User';
|
||||
|
||||
const DiscordOAuth = () => {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
const [userState, userDispatch] = useContext(UserContext);
|
||||
const [prompt, setPrompt] = useState('处理中...');
|
||||
const [processing, setProcessing] = useState(true);
|
||||
|
||||
let navigate = useNavigate();
|
||||
|
||||
const sendCode = async (code, count) => {
|
||||
const res = await API.get(`/api/oauth/discord?code=${code}`);
|
||||
const { success, message, data } = res.data;
|
||||
if (success) {
|
||||
if (message === 'bind') {
|
||||
showSuccess('绑定成功!');
|
||||
navigate('/setting');
|
||||
} else {
|
||||
userDispatch({ type: 'login', payload: data });
|
||||
localStorage.setItem('user', JSON.stringify(data));
|
||||
showSuccess('登录成功!');
|
||||
navigate('/');
|
||||
}
|
||||
} else {
|
||||
showError(message);
|
||||
if (count === 0) {
|
||||
setPrompt(`操作失败,重定向至登录界面中...`);
|
||||
navigate('/setting'); // in case this is failed to bind GitHub
|
||||
return;
|
||||
}
|
||||
count++;
|
||||
setPrompt(`出现错误,第 ${count} 次重试中...`);
|
||||
await new Promise((resolve) => setTimeout(resolve, count * 2000));
|
||||
await sendCode(code, count);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let code = searchParams.get('code');
|
||||
sendCode(code, 0).then();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Segment style={{ minHeight: '300px' }}>
|
||||
<Dimmer active inverted>
|
||||
<Loader size='large'>{prompt}</Loader>
|
||||
</Dimmer>
|
||||
</Segment>
|
||||
);
|
||||
};
|
||||
|
||||
export default DiscordOAuth;
|
||||
@@ -57,6 +57,12 @@ const LoginForm = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const onDiscordOAuthClicked = () => {
|
||||
window.open(
|
||||
`https://discord.com/oauth2/authorize?response_type=code&client_id=${status.discord_client_id}&redirect_uri=${window.location.origin}/oauth/discord&scope=identify`
|
||||
);
|
||||
};
|
||||
|
||||
const onWeChatLoginClicked = () => {
|
||||
setShowWeChatLoginModal(true);
|
||||
};
|
||||
@@ -158,28 +164,32 @@ const LoginForm = () => {
|
||||
点击注册
|
||||
</Link>
|
||||
</Message>
|
||||
{status.github_oauth || status.wechat_login ? (
|
||||
{status.github_oauth || status.wechat_login || status.discord_oauth ? (
|
||||
<>
|
||||
<Divider horizontal>Or</Divider>
|
||||
{status.github_oauth ? (
|
||||
{status.discord_oauth && (
|
||||
<Button
|
||||
circular
|
||||
color="blue"
|
||||
icon="discord"
|
||||
onClick={onDiscordOAuthClicked}
|
||||
/>
|
||||
)}
|
||||
{status.github_oauth && (
|
||||
<Button
|
||||
circular
|
||||
color="black"
|
||||
icon="github"
|
||||
onClick={onGitHubOAuthClicked}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{status.wechat_login ? (
|
||||
{status.wechat_login && (
|
||||
<Button
|
||||
circular
|
||||
color="green"
|
||||
icon="wechat"
|
||||
onClick={onWeChatLoginClicked}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
|
||||
@@ -77,6 +77,12 @@ const PersonalSetting = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const openDiscordOAuth = () => {
|
||||
window.open(
|
||||
`https://discord.com/api/oauth2/authorize?client_id=${status.discord_client_id}&scope=identify%20email&response_type=code&redirect_uri=${window.location.origin}/oauth/discord`
|
||||
);
|
||||
}
|
||||
|
||||
const sendVerificationCode = async () => {
|
||||
if (inputs.email === '') return;
|
||||
if (turnstileEnabled && turnstileToken === '') {
|
||||
@@ -170,6 +176,11 @@ const PersonalSetting = () => {
|
||||
<Button onClick={openGitHubOAuth}>绑定 GitHub 账号</Button>
|
||||
)
|
||||
}
|
||||
{
|
||||
status.discord_oauth && (
|
||||
<Button onClick={openDiscordOAuth}>绑定 Discord 账号</Button>
|
||||
)
|
||||
}
|
||||
<Button
|
||||
onClick={() => {
|
||||
setShowEmailBindModal(true);
|
||||
|
||||
@@ -8,8 +8,11 @@ const SystemSetting = () => {
|
||||
PasswordRegisterEnabled: '',
|
||||
EmailVerificationEnabled: '',
|
||||
GitHubOAuthEnabled: '',
|
||||
DiscordOAuthEnabled: '',
|
||||
GitHubClientId: '',
|
||||
GitHubClientSecret: '',
|
||||
DiscordClientId: '',
|
||||
DiscordClientSecret: '',
|
||||
Notice: '',
|
||||
SMTPServer: '',
|
||||
SMTPPort: '',
|
||||
@@ -56,6 +59,7 @@ const SystemSetting = () => {
|
||||
case 'PasswordRegisterEnabled':
|
||||
case 'EmailVerificationEnabled':
|
||||
case 'GitHubOAuthEnabled':
|
||||
case 'DiscordOAuthEnabled':
|
||||
case 'WeChatAuthEnabled':
|
||||
case 'TurnstileCheckEnabled':
|
||||
case 'RegisterEnabled':
|
||||
@@ -82,6 +86,8 @@ const SystemSetting = () => {
|
||||
name === 'Notice' ||
|
||||
name.startsWith('SMTP') ||
|
||||
name === 'ServerAddress' ||
|
||||
name === 'DiscordClientId' ||
|
||||
name === 'DiscordClientSecret' ||
|
||||
name === 'GitHubClientId' ||
|
||||
name === 'GitHubClientSecret' ||
|
||||
name === 'WeChatServerAddress' ||
|
||||
@@ -161,6 +167,18 @@ const SystemSetting = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const submitDiscordOAuth = async () => {
|
||||
if (originInputs['DiscordClientId'] !== inputs.DiscordClientId) {
|
||||
await updateOption('DiscordClientId', inputs.DiscordClientId);
|
||||
}
|
||||
if (
|
||||
originInputs['DiscordClientSecret'] !== inputs.DiscordClientSecret &&
|
||||
inputs.DiscordClientSecret !== ''
|
||||
) {
|
||||
await updateOption('DiscordClientSecret', inputs.DiscordClientSecret);
|
||||
}
|
||||
};
|
||||
|
||||
const submitTurnstile = async () => {
|
||||
if (originInputs['TurnstileSiteKey'] !== inputs.TurnstileSiteKey) {
|
||||
await updateOption('TurnstileSiteKey', inputs.TurnstileSiteKey);
|
||||
@@ -217,6 +235,12 @@ const SystemSetting = () => {
|
||||
name='GitHubOAuthEnabled'
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<Form.Checkbox
|
||||
checked={inputs.DiscordOAuthEnabled === 'true'}
|
||||
label='允许通过 Discord 账户登录 & 注册'
|
||||
name='DiscordOAuthEnabled'
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<Form.Checkbox
|
||||
checked={inputs.WeChatAuthEnabled === 'true'}
|
||||
label='允许通过微信登录 & 注册'
|
||||
@@ -290,6 +314,44 @@ const SystemSetting = () => {
|
||||
</Form.Group>
|
||||
<Form.Button onClick={submitSMTP}>保存 SMTP 设置</Form.Button>
|
||||
<Divider />
|
||||
<Header as='h3'>
|
||||
配置 Discord OAuth App
|
||||
<Header.Subheader>
|
||||
用以支持通过 GitHub 进行登录注册,
|
||||
<a href='https://discord.com/developers/applications' target='_blank'>
|
||||
点击此处
|
||||
</a>
|
||||
管理你的 Discord OAuth App
|
||||
</Header.Subheader>
|
||||
</Header>
|
||||
<Message>
|
||||
Homepage URL 填 <code>{inputs.ServerAddress}</code>
|
||||
,Authorization callback URL 填{' '}
|
||||
<code>{`${inputs.ServerAddress}/oauth/discord`}</code>
|
||||
</Message>
|
||||
<Form.Group widths={3}>
|
||||
<Form.Input
|
||||
label='Discord Client ID'
|
||||
name='DiscordClientId'
|
||||
onChange={handleInputChange}
|
||||
autoComplete='new-password'
|
||||
value={inputs.DiscordClientId}
|
||||
placeholder='输入你注册的 Discord OAuth APP 的 ID'
|
||||
/>
|
||||
<Form.Input
|
||||
label='Discord Client Secret'
|
||||
name='DiscordClientSecret'
|
||||
onChange={handleInputChange}
|
||||
type='password'
|
||||
autoComplete='new-password'
|
||||
value={inputs.DiscordClientSecret}
|
||||
placeholder='敏感信息不会发送到前端显示'
|
||||
/>
|
||||
</Form.Group>
|
||||
<Form.Button onClick={submitDiscordOAuth}>
|
||||
保存 Discord OAuth 设置
|
||||
</Form.Button>
|
||||
<Divider />
|
||||
<Header as='h3'>
|
||||
配置 GitHub OAuth App
|
||||
<Header.Subheader>
|
||||
|
||||
@@ -97,6 +97,12 @@ const Home = () => {
|
||||
? '已启用'
|
||||
: '未启用'}
|
||||
</p>
|
||||
<p>
|
||||
Discord 身份验证:
|
||||
{statusState?.status?.discord_oauth === true
|
||||
? '已启用'
|
||||
: '未启用'}
|
||||
</p>
|
||||
<p>
|
||||
微信身份验证:
|
||||
{statusState?.status?.wechat_login === true
|
||||
|
||||
Reference in New Issue
Block a user