v0.1.0
This commit is contained in:
250
src/pages/OAuthAuthorize.jsx
Normal file
250
src/pages/OAuthAuthorize.jsx
Normal file
@ -0,0 +1,250 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { useSearchParams, useNavigate } from 'react-router-dom'
|
||||
import { useAuth } from '../contexts/AuthContext'
|
||||
import {
|
||||
Container,
|
||||
Paper,
|
||||
Typography,
|
||||
Box,
|
||||
Button,
|
||||
Grid,
|
||||
Card,
|
||||
CardContent,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Chip,
|
||||
Alert,
|
||||
CircularProgress
|
||||
} from '@mui/material'
|
||||
import {
|
||||
Security,
|
||||
CheckCircle,
|
||||
Cancel,
|
||||
Person,
|
||||
Email,
|
||||
CalendarToday,
|
||||
Visibility,
|
||||
VisibilityOff
|
||||
} from '@mui/icons-material'
|
||||
import axios from 'axios'
|
||||
|
||||
const OAuthAuthorize = () => {
|
||||
const { user } = useAuth()
|
||||
const [searchParams] = useSearchParams()
|
||||
const navigate = useNavigate()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const [clientInfo, setClientInfo] = useState(null)
|
||||
|
||||
const clientId = searchParams.get('client_id')
|
||||
const redirectUri = searchParams.get('redirect_uri')
|
||||
const scope = searchParams.get('scope')
|
||||
const state = searchParams.get('state')
|
||||
const responseType = searchParams.get('response_type')
|
||||
|
||||
useEffect(() => {
|
||||
if (!user) {
|
||||
navigate('/login')
|
||||
return
|
||||
}
|
||||
|
||||
if (!clientId || !redirectUri || responseType !== 'code') {
|
||||
setError('无效的授权请求')
|
||||
return
|
||||
}
|
||||
|
||||
// 这里可以添加客户端信息获取逻辑
|
||||
// 为了演示,我们使用默认信息
|
||||
setClientInfo({
|
||||
name: '第三方应用',
|
||||
description: '请求访问您的账户信息',
|
||||
scopes: scope ? scope.split(' ') : ['read', 'write']
|
||||
})
|
||||
}, [user, clientId, redirectUri, scope, responseType, navigate])
|
||||
|
||||
const handleAuthorize = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
response_type: 'code',
|
||||
client_id: clientId,
|
||||
redirect_uri: redirectUri,
|
||||
scope: scope || 'read write',
|
||||
state: state || ''
|
||||
})
|
||||
|
||||
const response = await axios.get(`/api/oauth/authorize?${params}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem('token')}`
|
||||
}
|
||||
})
|
||||
|
||||
if (response.data.success) {
|
||||
const { redirect_url } = response.data.data
|
||||
window.location.href = redirect_url
|
||||
}
|
||||
} catch (error) {
|
||||
setError(error.response?.data?.message || '授权失败')
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const handleDeny = () => {
|
||||
// 拒绝授权,重定向回应用
|
||||
const denyUrl = new URL(redirectUri)
|
||||
denyUrl.searchParams.set('error', 'access_denied')
|
||||
if (state) {
|
||||
denyUrl.searchParams.set('state', state)
|
||||
}
|
||||
window.location.href = denyUrl.toString()
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return (
|
||||
<Container maxWidth="sm">
|
||||
<Box
|
||||
sx={{
|
||||
minHeight: '100vh',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Container maxWidth="sm">
|
||||
<Box
|
||||
sx={{
|
||||
minHeight: '100vh',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{
|
||||
p: 4,
|
||||
width: '100%',
|
||||
maxWidth: 500
|
||||
}}
|
||||
>
|
||||
<Box textAlign="center" mb={3}>
|
||||
<Security sx={{ fontSize: 48, color: 'primary.main', mb: 2 }} />
|
||||
<Typography variant="h4" component="h1" gutterBottom>
|
||||
授权请求
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
第三方应用请求访问您的账户
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{error && (
|
||||
<Alert severity="error" sx={{ mb: 2 }}>
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{clientInfo && (
|
||||
<>
|
||||
{/* 应用信息 */}
|
||||
<Card variant="outlined" sx={{ mb: 3 }}>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
{clientInfo.name}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||
{clientInfo.description}
|
||||
</Typography>
|
||||
<Box mt={2}>
|
||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||
请求的权限:
|
||||
</Typography>
|
||||
{clientInfo.scopes.map((scope) => (
|
||||
<Chip
|
||||
key={scope}
|
||||
label={scope === 'read' ? '读取信息' : scope === 'write' ? '写入信息' : scope}
|
||||
size="small"
|
||||
sx={{ mr: 0.5, mb: 0.5 }}
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 用户信息 */}
|
||||
<Card variant="outlined" sx={{ mb: 3 }}>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
您的账户信息
|
||||
</Typography>
|
||||
<List dense>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<Person />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="用户名" secondary={user.username} />
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<Email />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="邮箱" secondary={user.email} />
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<CalendarToday />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary="注册时间"
|
||||
secondary={new Date(user.created_at).toLocaleDateString()}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 操作按钮 */}
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
color="error"
|
||||
startIcon={<Cancel />}
|
||||
onClick={handleDeny}
|
||||
disabled={loading}
|
||||
>
|
||||
拒绝
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
startIcon={<CheckCircle />}
|
||||
onClick={handleAuthorize}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? '授权中...' : '授权'}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
</Paper>
|
||||
</Box>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default OAuthAuthorize
|
Reference in New Issue
Block a user