Ver código fonte

add: oauth2 of token

dev
powersir 1 ano atrás
pai
commit
50867fc3fa
4 arquivos alterados com 345 adições e 0 exclusões
  1. +1
    -0
      src/models/index.ts
  2. +42
    -0
      src/models/oauth2.data.ts
  3. +258
    -0
      src/pages/system/oauth2/token/index.tsx
  4. +44
    -0
      src/request/service/oauth2.ts

+ 1
- 0
src/models/index.ts Ver arquivo

@@ -10,6 +10,7 @@ export * from './system-dict.data.ts'
export * from './error-code.data.ts'
export * from './redis.data.ts'
export * from './api-log.data.ts'
export * from './oauth2.data.ts'

export interface ResponseDTO<T>{
code: number;


+ 42
- 0
src/models/oauth2.data.ts Ver arquivo

@@ -0,0 +1,42 @@
export interface OAuth2TokenVO {
id: number
accessToken: string
refreshToken: string
userId: number
userType: number
clientId: string
createTime: Date
expiresTime: Date
}

export interface OAuth2TokenPageReqVO extends PageParam {
userId?: number
userType?: number
clientId?: string
}

export interface OAuth2ClientVO {
id: number
clientId: string
secret: string
name: string
logo: string
description: string
status: number
accessTokenValiditySeconds: number
refreshTokenValiditySeconds: number
redirectUris: string[]
autoApprove: boolean
authorizedGrantTypes: string[]
scopes: string[]
authorities: string[]
resourceIds: string[]
additionalInformation: string
isAdditionalInformationJson: boolean
createTime: Date
}

export interface OAuth2ClientPageReqVO extends PageParam {
name?: string
status?: number
}

+ 258
- 0
src/pages/system/oauth2/token/index.tsx Ver arquivo

@@ -0,0 +1,258 @@
import React, { useState, useEffect, useRef } from 'react';
import { useSetState } from 'ahooks';
import { Space, Table, Input, Divider, Tag, Card } from 'antd';
import type { TableColumnsType, InputRef } from 'antd';
import type { ColumnType, TableProps } from 'antd/es/table';
import { t } from '@/utils/i18n';
import { SearchOutlined, ExclamationCircleFilled } from '@ant-design/icons';
import { antdUtils } from '@/utils/antd';
import { useRequest } from '@/hooks/use-request';
import { formatDate } from '@/utils/formatTime'
import oauth2Service from '@/request/service/oauth2';
import {
OAuth2TokenVO,
OAuth2TokenPageReqVO
} from '@/models';


type DataIndex = keyof OAuth2TokenVO;

const mapOperation = (operation: number) => {
if (operation === 1) {
return (<Tag color="purple">通知</Tag>)
} else if (operation === 2) {
return (<Tag color="purple">新增</Tag>)
} else if (operation === 3) {
return (<Tag color="yellow">修改</Tag>)
} else if (operation === 4) {
return (<Tag color="red">删除</Tag>)
} else if (operation === 5) {
return (<Tag color="blue">导出</Tag>)
} else {
return (<Tag color="red">未知({operation})</Tag>)
}
}

export default () => {
const [dataSource, setDataSource] = useState<OAuth2TokenVO[]>([]);

const { runAsync: getPageData } = useRequest(oauth2Service.getAccessTokenPageApi, { manual: true });
const { runAsync: deleteAccessToken } = useRequest(oauth2Service.deleteAccessTokenApi, { manual: true });

const [searchState, setSearchState] = useSetState<OAuth2TokenPageReqVO>({
pageNo: 1,
pageSize: 10
});
const [total, setTotal] = useState(0)
const searchInput = useRef<InputRef>(null);
const [onSearching, setOnSearching] = useState(false);

const load = async () => {
console.log(searchState)
const [error, { code, msg, data }] = await getPageData(searchState);
setOnSearching(false);
if (error || code !== 0) {
antdUtils.message?.open({ type: 'error', content: msg ?? '操作失败' });
return
}
setTotal(data.total);
setDataSource(data.list);
};

const getColumnSearchProps = (dataIndex: DataIndex, placeholder: string): ColumnType<OAuth2TokenVO> => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }) => (
<div style={{ padding: 8 }} onKeyDown={(e) => e.stopPropagation()}>
<Input.Search
ref={searchInput}
placeholder={placeholder}
value={selectedKeys[0]}
onChange={(e) => {
setSelectedKeys(e.target.value && e.target.value !== '' ? [e.target.value] : [])
}}
onSearch={(value) => {
if (value === '' && clearFilters) {
clearFilters!!()
}
confirm();
}}
onPressEnter={() => confirm()}
allowClear
style={{ marginBottom: 8, display: 'block' }}
enterButton="搜索"
size="middle"
loading={onSearching}
/>
</div>
),
filterIcon: (filtered: boolean) => (
<SearchOutlined style={{ color: filtered ? 'primaryColor' : undefined }} />
),
onFilterDropdownOpenChange: (visible) => {
if (visible) {
setTimeout(() => searchInput.current?.select(), 100);
}
},
});

const forceQuite = async (params: OAuth2TokenVO) => {
antdUtils.modal?.confirm({
title: '系统提示',
icon: <ExclamationCircleFilled />,
content: '是否要强制退出用户',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
return new Promise(async (resolve) => {
const [error, { code, msg }] = await deleteAccessToken(params.accessToken);
if (error || code !== 0) {
antdUtils.message?.open({ type: 'error', content: msg ?? '操作失败' })
} else {
antdUtils.message?.open({ type: 'success', content: '操作成功' })
}
resolve('');
await load();
}).catch(() => antdUtils.message?.open({
type: 'error',
content: '操作失败',
}));
},
onCancel() {
},
});
}

const columns: TableColumnsType<OAuth2TokenVO> = [
{
title: '用户编号',
dataIndex: 'userId',
key: 'userId',
align: 'center',
width: 100,
...getColumnSearchProps('userId', "请输入用户编号")
},
{
title: '访问令牌',
dataIndex: 'accessToken',
key: 'accessToken',
align: 'center',
width: 120,
},
{
title: '刷新令牌',
dataIndex: 'refreshToken',
key: 'refreshToken',
align: 'center',
width: 100,
},

{
title: '客户端编号',
dataIndex: 'clientId',
key: 'clientId',
align: 'center',
width: 150,
...getColumnSearchProps('clientId', "客户端编号")
},
{
title: '用户类型',
dataIndex: 'userType',
key: 'userType',
fixed: 'left',
align: 'center',
width: 100,
filters: [
{ text: '会员', value: 1 },
{ text: '管理员', value: 2 },
],
filterMultiple: false,
filterSearch: false,
render: (value: number) => {
if (value === 1) {
return <Tag color="purple">会员</Tag>
} else if (value === 2) {
return <Tag color="blue">管理员</Tag>
} else {
return <Tag color="red">未知</Tag>
}
}
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
width: 150,
render: (value: number) => {
return formatDate(new Date(value), "YYYY-mm-dd HH:MM:SS")
}
},
{
title: '过期时间',
dataIndex: 'expiresTime',
key: 'expiresTime',
align: 'center',
width: 150,
render: (value: number) => {
return formatDate(new Date(value), "YYYY-mm-dd HH:MM:SS")
}
},
{
title: t("QkOmYwne" /* 操作 */),
key: 'action',
fixed: 'right',
align: 'center',
width: 250,
render: (value: OAuth2TokenVO, record) => (
<Space size="small" split={(<Divider type='vertical' />)}>
<a onClick={() => {

}}> 详情 </a>

<a onClick={() => {
forceQuite(value)
}}> 强制退出 </a>
</Space>
),
},
];

useEffect(() => {
load();
}, [searchState]);

const onChange: TableProps<OAuth2TokenVO>['onChange'] = (pagination, filters, sorter, extra) => {
const state: OAuth2TokenPageReqVO = {
clientId: filters.clientId ? filters.clientId[0] as string : undefined,
userId: filters.userId ? parseInt(filters.userId[0] as string) : undefined,
userType: filters.userType ? filters.userType[0] as number : undefined,
pageNo: pagination.current,
pageSize: pagination.pageSize
}
setOnSearching(true);
setSearchState(state);
};

return (
<>
<div>
<Card className='mt-[4px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]'>
<Table rowKey="id"
scroll={{ x: true }}
columns={columns}
dataSource={dataSource}
onChange={onChange}
className='bg-transparent'
pagination={{
position: ['bottomRight'],
current: searchState.pageNo,
pageSize: searchState.pageSize,
total
}}
/>
</Card>
</div>
</>
);
};

+ 44
- 0
src/request/service/oauth2.ts Ver arquivo

@@ -0,0 +1,44 @@
import request from '@/request';
import { OAuth2ClientVO, OAuth2TokenPageReqVO, OAuth2TokenVO, OAuth2ClientPageReqVO, PageData } from '@/models';

const BASE_TOKEN_URL = '/admin-api/system/oauth2-token';
const BASE_CLIENT_URL = '/admin-api/system/oauth2-client';

export default {
// 查询 token列表
getAccessTokenPageApi: (params: OAuth2TokenPageReqVO) => {
return request.get<PageData<OAuth2TokenVO>>(`${BASE_TOKEN_URL}/page`, {params})
},

// 删除 token
deleteAccessTokenApi: (accessToken: number) => {
return request.delete(`${BASE_TOKEN_URL}/delete?accessToken=${accessToken}`)
},

// 查询 OAuth2列表
getOAuth2ClientPageApi: (params: OAuth2ClientPageReqVO) => {
return request.get<PageData<OAuth2ClientVO>>(`${BASE_CLIENT_URL}/page`, {params})
},

// 查询 OAuth2详情
getOAuth2ClientApi: (id: number) => {
return request.get<OAuth2ClientVO>(`${BASE_CLIENT_URL}/get?id=${id}`)
},

// 新增 OAuth2
createOAuth2ClientApi: (data: OAuth2ClientVO) => {
return request.post(`${BASE_CLIENT_URL}/create`, data)
},

// 修改 OAuth2
updateOAuth2ClientApi: (data: OAuth2ClientVO) => {
return request.put(`${BASE_CLIENT_URL}/update`, data)
},

// 删除 OAuth2
deleteOAuth2ClientApi: (id: number) => {
return request.delete(`${BASE_CLIENT_URL}/delete?id=${id}`)
},

};


Carregando…
Cancelar
Salvar