feat: integrate Linux DO OAuth authentication

This commit is contained in:
seefs001
2024-11-10 23:56:22 +08:00
parent 3b53a2a5ce
commit 046f859d92
13 changed files with 978 additions and 542 deletions

View File

@@ -1,8 +1,15 @@
import React, { useContext, useEffect, useState } from 'react';
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
import { UserContext } from '../context/User';
import { API, getLogo, showError, showInfo, showSuccess, updateAPI } from '../helpers';
import { onGitHubOAuthClicked } from './utils';
import {
API,
getLogo,
showError,
showInfo,
showSuccess,
updateAPI,
} from '../helpers';
import { onGitHubOAuthClicked, onLinuxDOOAuthClicked } from './utils';
import Turnstile from 'react-turnstile';
import {
Button,
@@ -17,7 +24,7 @@ import Title from '@douyinfe/semi-ui/lib/es/typography/title';
import Text from '@douyinfe/semi-ui/lib/es/typography/text';
import TelegramLoginButton from 'react-telegram-login';
import { IconGithubLogo } from '@douyinfe/semi-icons';
import { IconGithubLogo, IconAlarm } from '@douyinfe/semi-icons';
import WeChatIcon from './WeChatIcon';
import { setUserData } from '../helpers/data.js';
@@ -72,7 +79,7 @@ const LoginForm = () => {
userDispatch({ type: 'login', payload: data });
localStorage.setItem('user', JSON.stringify(data));
setUserData(data);
updateAPI()
updateAPI();
navigate('/');
showSuccess('登录成功!');
setShowWeChatLoginModal(false);
@@ -103,7 +110,7 @@ const LoginForm = () => {
if (success) {
userDispatch({ type: 'login', payload: data });
setUserData(data);
updateAPI()
updateAPI();
showSuccess('登录成功!');
if (username === 'root' && password === '123456') {
Modal.error({
@@ -146,7 +153,7 @@ const LoginForm = () => {
localStorage.setItem('user', JSON.stringify(data));
showSuccess('登录成功!');
setUserData(data);
updateAPI()
updateAPI();
navigate('/');
} else {
showError(message);
@@ -214,7 +221,8 @@ const LoginForm = () => {
</div>
{status.github_oauth ||
status.wechat_login ||
status.telegram_oauth ? (
status.telegram_oauth ||
status.linuxdo_oauth ? (
<>
<Divider margin='12px' align='center'>
第三方登录
@@ -237,6 +245,17 @@ const LoginForm = () => {
) : (
<></>
)}
{status.linuxdo_oauth ? (
<Button
type='primary'
icon={<IconAlarm />}
onClick={() =>
onLinuxDOOAuthClicked(status.linuxdo_client_id)
}
/>
) : (
<></>
)}
{status.wechat_login ? (
<Button
type='primary'

View File

@@ -10,7 +10,7 @@ import {
} from '../helpers';
import Turnstile from 'react-turnstile';
import { UserContext } from '../context/User';
import { onGitHubOAuthClicked } from './utils';
import { onGitHubOAuthClicked, onLinuxDOOAuthClicked } from './utils';
import {
Avatar,
Banner,
@@ -519,7 +519,6 @@ const PersonalSetting = () => {
</div>
</div>
</div>
<div style={{ marginTop: 10 }}>
<Typography.Text strong>Telegram</Typography.Text>
<div
@@ -551,7 +550,36 @@ const PersonalSetting = () => {
</div>
</div>
</div>
<div style={{ marginTop: 10 }}>
<Typography.Text strong>LinuxDO</Typography.Text>
<div
style={{ display: 'flex', justifyContent: 'space-between' }}
>
<div>
<Input
value={
userState.user && userState.user.linux_do_id !== ''
? userState.user.linux_do_id
: '未绑定'
}
readonly={true}
></Input>
</div>
<div>
<Button
onClick={() => {
onLinuxDOOAuthClicked(status.linuxdo_client_id);
}}
disabled={
(userState.user && userState.user.linux_do_id !== '') ||
!status.linuxdo_oauth
}
>
{status.linuxdo_oauth ? '绑定' : '未启用'}
</Button>
</div>
</div>
</div>
<div style={{ marginTop: 10 }}>
<Space>
<Button onClick={generateAccessToken}>

View File

@@ -53,6 +53,9 @@ const SystemSetting = () => {
TelegramOAuthEnabled: '',
TelegramBotToken: '',
TelegramBotName: '',
LinuxDOOAuthEnabled: '',
LinuxDOClientId: '',
LinuxDOClientSecret: '',
});
const [originInputs, setOriginInputs] = useState({});
let [loading, setLoading] = useState(false);
@@ -103,6 +106,7 @@ const SystemSetting = () => {
case 'PasswordRegisterEnabled':
case 'EmailVerificationEnabled':
case 'GitHubOAuthEnabled':
case 'LinuxDOOAuthEnabled':
case 'WeChatAuthEnabled':
case 'TelegramOAuthEnabled':
case 'TurnstileCheckEnabled':
@@ -163,7 +167,9 @@ const SystemSetting = () => {
name === 'EmailDomainWhitelist' ||
name === 'TopupGroupRatio' ||
name === 'TelegramBotToken' ||
name === 'TelegramBotName'
name === 'TelegramBotName' ||
name === 'LinuxDOClientId' ||
name === 'LinuxDOClientSecret'
) {
setInputs((inputs) => ({ ...inputs, [name]: value }));
} else {
@@ -182,7 +188,7 @@ const SystemSetting = () => {
if (inputs.WorkerValidKey !== '') {
await updateOption('WorkerValidKey', inputs.WorkerValidKey);
}
}
};
const submitPayAddress = async () => {
if (inputs.ServerAddress === '') {
@@ -320,6 +326,18 @@ const SystemSetting = () => {
}
};
const submitLinuxDOOAuth = async () => {
if (originInputs['LinuxDOClientId'] !== inputs.LinuxDOClientId) {
await updateOption('LinuxDOClientId', inputs.LinuxDOClientId);
}
if (
originInputs['LinuxDOClientSecret'] !== inputs.LinuxDOClientSecret &&
inputs.LinuxDOClientSecret !== ''
) {
await updateOption('LinuxDOClientSecret', inputs.LinuxDOClientSecret);
}
};
return (
<Grid columns={1}>
<Grid.Column>
@@ -340,7 +358,15 @@ const SystemSetting = () => {
更新服务器地址
</Form.Button>
<Header as='h3' inverted={isDark}>
代理设置支持 <a href='https://github.com/Calcium-Ion/new-api-worker' target='_blank' rel='noreferrer'>new-api-worker</a>
代理设置支持{' '}
<a
href='https://github.com/Calcium-Ion/new-api-worker'
target='_blank'
rel='noreferrer'
>
new-api-worker
</a>
</Header>
<Form.Group widths='equal'>
<Form.Input
@@ -358,9 +384,7 @@ const SystemSetting = () => {
onChange={handleInputChange}
/>
</Form.Group>
<Form.Button onClick={submitWorker}>
更新Worker设置
</Form.Button>
<Form.Button onClick={submitWorker}>更新Worker设置</Form.Button>
<Divider />
<Header as='h3' inverted={isDark}>
支付设置当前仅支持易支付接口默认使用上方服务器地址作为回调地址
@@ -483,6 +507,12 @@ const SystemSetting = () => {
name='GitHubOAuthEnabled'
onChange={handleInputChange}
/>
<Form.Checkbox
checked={inputs.LinuxDOOAuthEnabled === 'true'}
label='允许通过 LinuxDO 账户登录 & 注册'
name='LinuxDOOAuthEnabled'
onChange={handleInputChange}
/>
<Form.Checkbox
checked={inputs.WeChatAuthEnabled === 'true'}
label='允许通过微信登录 & 注册'
@@ -781,6 +811,48 @@ const SystemSetting = () => {
<Form.Button onClick={submitTurnstile}>
保存 Turnstile 设置
</Form.Button>
<Divider />
<Header as='h3' inverted={isDark}>
配置 LinuxDO OAuth App
<Header.Subheader>
用以支持通过 LinuxDO 进行登录注册
<a
href='https://connect.linux.do/'
target='_blank'
rel='noreferrer'
>
点击此处
</a>
管理你的 LinuxDO OAuth App
</Header.Subheader>
</Header>
<Message>
Homepage URL <code>{inputs.ServerAddress}</code>
Authorization callback URL {' '}
<code>{`${inputs.ServerAddress}/oauth/linuxdo`}</code>
</Message>
<Form.Group widths={3}>
<Form.Input
label='LinuxDO Client ID'
name='LinuxDOClientId'
onChange={handleInputChange}
autoComplete='new-password'
value={inputs.LinuxDOClientId}
placeholder='输入你注册的 LinuxDO OAuth APP 的 ID'
/>
<Form.Input
label='LinuxDO Client Secret'
name='LinuxDOClientSecret'
onChange={handleInputChange}
type='password'
autoComplete='new-password'
value={inputs.LinuxDOClientSecret}
placeholder='敏感信息不会发送到前端显示'
/>
</Form.Group>
<Form.Button onClick={submitLinuxDOOAuth}>
保存 LinuxDO OAuth 设置
</Form.Button>
</Form>
</Grid.Column>
</Grid>

View File

@@ -19,6 +19,14 @@ export async function onGitHubOAuthClicked(github_client_id) {
);
}
export async function onLinuxDOOAuthClicked(linuxdo_client_id) {
const state = await getOAuthState();
if (!state) return;
window.open(
`https://connect.linux.do/oauth2/authorize?response_type=code&client_id=${linuxdo_client_id}&state=${state}`,
);
}
let channelModels = undefined;
export async function loadChannelModels() {
const res = await API.get('/api/models');

View File

@@ -150,6 +150,12 @@ const Home = () => {
? '已启用'
: '未启用'}
</p>
<p>
Linux DO 身份验证
{statusState?.status?.linuxdo_oauth === true
? '已启用'
: '未启用'}
</p>
</Card>
</Col>
</Row>