Merge pull request #16 from yumusb/feat/hide-login-form
feat: Add `passwordEnabled` configuration to conditionally display th…
This commit is contained in:
3 files changed
+64
-58
No files matched your search
@@ -167,15 +167,17 @@ func (s *AccountService) ValidateToken(tokenString string) (*JWTClaims, error) {
|
|||||||
|
|
||||||
// AuthConfig 认证配置
|
// AuthConfig 认证配置
|
||||||
type AuthConfig struct {
|
type AuthConfig struct {
|
||||||
OIDCEnabled bool `json:"oidcEnabled"`
|
OIDCEnabled bool `json:"oidcEnabled"`
|
||||||
GitHubEnabled bool `json:"githubEnabled"`
|
GitHubEnabled bool `json:"githubEnabled"`
|
||||||
|
PasswordEnabled bool `json:"passwordEnabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAuthConfig 获取认证配置
|
// GetAuthConfig 获取认证配置
|
||||||
func (s *AccountService) GetAuthConfig() *AuthConfig {
|
func (s *AccountService) GetAuthConfig() *AuthConfig {
|
||||||
return &AuthConfig{
|
return &AuthConfig{
|
||||||
OIDCEnabled: s.oidcService.IsEnabled(),
|
OIDCEnabled: s.oidcService.IsEnabled(),
|
||||||
GitHubEnabled: s.githubService.IsEnabled(),
|
GitHubEnabled: s.githubService.IsEnabled(),
|
||||||
|
PasswordEnabled: s.userService.IsEnabled(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type { LoginRequest, LoginResponse } from '../types';
|
|||||||
export interface AuthConfig {
|
export interface AuthConfig {
|
||||||
oidcEnabled: boolean;
|
oidcEnabled: boolean;
|
||||||
githubEnabled: boolean;
|
githubEnabled: boolean;
|
||||||
|
passwordEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OIDC 认证 URL
|
// OIDC 认证 URL
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
import {useEffect, useState} from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import {useNavigate} from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import {App, Button, Form, Input} from 'antd';
|
import { App, Button, Form, Input } from 'antd';
|
||||||
import {GithubOutlined, GlobalOutlined, LockOutlined, UserOutlined} from '@ant-design/icons';
|
import { GithubOutlined, GlobalOutlined, LockOutlined, UserOutlined } from '@ant-design/icons';
|
||||||
import {getAuthConfig, getGitHubAuthURL, getOIDCAuthURL, login} from '@/api/auth.ts';
|
import { getAuthConfig, getGitHubAuthURL, getOIDCAuthURL, login } from '@/api/auth.ts';
|
||||||
import type {LoginRequest} from '@/types';
|
import type { LoginRequest } from '@/types';
|
||||||
|
|
||||||
const Login = () => {
|
const Login = () => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [oidcEnabled, setOidcEnabled] = useState(false);
|
const [oidcEnabled, setOidcEnabled] = useState(false);
|
||||||
const [githubEnabled, setGithubEnabled] = useState(false);
|
const [githubEnabled, setGithubEnabled] = useState(false);
|
||||||
|
const [passwordEnabled, setPasswordEnabled] = useState(true);
|
||||||
const [oidcLoading, setOidcLoading] = useState(false);
|
const [oidcLoading, setOidcLoading] = useState(false);
|
||||||
const [githubLoading, setGithubLoading] = useState(false);
|
const [githubLoading, setGithubLoading] = useState(false);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const {message: messageApi} = App.useApp();
|
const { message: messageApi } = App.useApp();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchAuthConfig();
|
fetchAuthConfig();
|
||||||
@@ -23,6 +24,7 @@ const Login = () => {
|
|||||||
const response = await getAuthConfig();
|
const response = await getAuthConfig();
|
||||||
setOidcEnabled(response.data.oidcEnabled);
|
setOidcEnabled(response.data.oidcEnabled);
|
||||||
setGithubEnabled(response.data.githubEnabled);
|
setGithubEnabled(response.data.githubEnabled);
|
||||||
|
setPasswordEnabled(response.data.passwordEnabled);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取认证配置失败:', error);
|
console.error('获取认证配置失败:', error);
|
||||||
}
|
}
|
||||||
@@ -32,7 +34,7 @@ const Login = () => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await login(values);
|
const response = await login(values);
|
||||||
const {token, user} = response.data;
|
const { token, user } = response.data;
|
||||||
localStorage.setItem('token', token);
|
localStorage.setItem('token', token);
|
||||||
localStorage.setItem('userInfo', JSON.stringify(user));
|
localStorage.setItem('userInfo', JSON.stringify(user));
|
||||||
messageApi.success('欢迎回来');
|
messageApi.success('欢迎回来');
|
||||||
@@ -83,60 +85,61 @@ const Login = () => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Form
|
{passwordEnabled && (
|
||||||
name="login"
|
<Form
|
||||||
layout="vertical"
|
name="login"
|
||||||
|
layout="vertical"
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
requiredMark={false} // 4. 隐藏必填星号,界面更干净
|
requiredMark={false} // 4. 隐藏必填星号,界面更干净
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
name="username"
|
|
||||||
rules={[{required: true, message: '请输入用户名'}]}
|
|
||||||
className="mb-4"
|
|
||||||
>
|
>
|
||||||
<Input
|
<Form.Item
|
||||||
prefix={<UserOutlined className="text-slate-400 mr-1"/>}
|
name="username"
|
||||||
placeholder="用户名"
|
rules={[{ required: true, message: '请输入用户名' }]}
|
||||||
className="rounded-xl px-4 py-2.5 bg-slate-50 border-slate-200 hover:bg-white focus:bg-white transition-all"
|
className="mb-4"
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
name="password"
|
|
||||||
rules={[{required: true, message: '请输入密码'}]}
|
|
||||||
className="mb-6"
|
|
||||||
>
|
|
||||||
<Input.Password
|
|
||||||
prefix={<LockOutlined className="text-slate-400 mr-1"/>}
|
|
||||||
placeholder="密码"
|
|
||||||
className="rounded-xl px-4 py-2.5 bg-slate-50 border-slate-200 hover:bg-white focus:bg-white transition-all"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item className="mb-0">
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
htmlType="submit"
|
|
||||||
loading={loading}
|
|
||||||
block
|
|
||||||
className="h-11 rounded-xl bg-slate-900 hover:bg-slate-800 font-medium shadow-sm transition-all"
|
|
||||||
>
|
>
|
||||||
登 录
|
<Input
|
||||||
</Button>
|
prefix={<UserOutlined className="text-slate-400 mr-1" />}
|
||||||
</Form.Item>
|
placeholder="用户名"
|
||||||
</Form>
|
className="rounded-xl px-4 py-2.5 bg-slate-50 border-slate-200 hover:bg-white focus:bg-white transition-all"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="password"
|
||||||
|
rules={[{ required: true, message: '请输入密码' }]}
|
||||||
|
className="mb-6"
|
||||||
|
>
|
||||||
|
<Input.Password
|
||||||
|
prefix={<LockOutlined className="text-slate-400 mr-1" />}
|
||||||
|
placeholder="密码"
|
||||||
|
className="rounded-xl px-4 py-2.5 bg-slate-50 border-slate-200 hover:bg-white focus:bg-white transition-all"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item className="mb-0">
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
htmlType="submit"
|
||||||
|
loading={loading}
|
||||||
|
block
|
||||||
|
className="h-11 rounded-xl bg-slate-900 hover:bg-slate-800 font-medium shadow-sm transition-all"
|
||||||
|
>
|
||||||
|
登 录
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 5. 第三方登录区域 */}
|
{/* 5. 第三方登录区域 */}
|
||||||
{(oidcEnabled || githubEnabled) && (
|
{(oidcEnabled || githubEnabled) && (
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="absolute inset-0 flex items-center">
|
<div className="absolute inset-0 flex items-center">
|
||||||
<span className="w-full border-t border-slate-200"/>
|
<span className="w-full border-t border-slate-200" />
|
||||||
</div>
|
</div>
|
||||||
<div className="relative flex justify-center text-xs uppercase">
|
<div className="relative flex justify-center text-xs uppercase">
|
||||||
<span className="bg-white px-2 text-slate-400">或者</span>
|
<span className="bg-white px-2 text-slate-400">{passwordEnabled ? '或者' : '使用第三方登录'}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -146,7 +149,7 @@ const Login = () => {
|
|||||||
<Button
|
<Button
|
||||||
block
|
block
|
||||||
loading={githubLoading}
|
loading={githubLoading}
|
||||||
icon={<GithubOutlined/>}
|
icon={<GithubOutlined />}
|
||||||
onClick={handleGitHubLogin}
|
onClick={handleGitHubLogin}
|
||||||
className={`h-10 rounded-xl border-slate-200 text-slate-700 font-medium hover:border-slate-300 hover:text-slate-900 ${!oidcEnabled ? 'col-span-2' : ''}`}
|
className={`h-10 rounded-xl border-slate-200 text-slate-700 font-medium hover:border-slate-300 hover:text-slate-900 ${!oidcEnabled ? 'col-span-2' : ''}`}
|
||||||
>
|
>
|
||||||
@@ -157,7 +160,7 @@ const Login = () => {
|
|||||||
<Button
|
<Button
|
||||||
block
|
block
|
||||||
loading={oidcLoading}
|
loading={oidcLoading}
|
||||||
icon={<GlobalOutlined/>} // 换了一个更通用的图标
|
icon={<GlobalOutlined />} // 换了一个更通用的图标
|
||||||
onClick={handleOIDCLogin}
|
onClick={handleOIDCLogin}
|
||||||
className={`h-10 rounded-xl border-slate-200 text-slate-700 font-medium hover:border-slate-300 hover:text-slate-900 ${!githubEnabled ? 'col-span-2' : ''}`}
|
className={`h-10 rounded-xl border-slate-200 text-slate-700 font-medium hover:border-slate-300 hover:text-slate-900 ${!githubEnabled ? 'col-span-2' : ''}`}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in new issue
Block a user