Browse Source

feat(vben5): user logout

- add a token revocation api
- the token is revoked when the user logs out
- add an logout button to the 404 page
pull/1309/head
colin 6 months ago
parent
commit
894d8d7dfe
  1. 21
      apps/vben5/apps/app-antd/src/store/auth.ts
  2. 46
      apps/vben5/apps/app-antd/src/views/_core/fallback/not-found.vue
  3. 25
      apps/vben5/packages/@abp/account/src/api/useTokenApi.ts
  4. 8
      apps/vben5/packages/@abp/account/src/types/token.ts

21
apps/vben5/apps/app-antd/src/store/auth.ts

@ -26,7 +26,7 @@ import { $t } from '#/locales';
export const useAuthStore = defineStore('auth', () => {
const { publish } = useEventBus();
const { loginApi, refreshTokenApi } = useTokenApi();
const { loginApi, refreshTokenApi, logoutApi } = useTokenApi();
const { loginApi: qrcodeLoginApi } = useQrCodeLoginApi();
const { loginApi: phoneLoginApi } = usePhoneLoginApi();
const { getUserInfoApi } = useUserInfoApi();
@ -131,6 +131,25 @@ export const useAuthStore = defineStore('auth', () => {
if (await oidcClient.getAccessToken()) {
accessStore.setAccessToken(null);
await oidcClient.logout();
} else {
const logoutTasks: Promise<void>[] = [];
if (accessStore.accessToken) {
logoutTasks.push(
logoutApi({
token: accessStore.accessToken,
tokenType: 'access_token',
}),
);
}
if (accessStore.refreshToken) {
logoutTasks.push(
logoutApi({
token: accessStore.refreshToken,
tokenType: 'refresh_token',
}),
);
}
await Promise.all(logoutTasks);
}
} catch {
// 不做任何处理

46
apps/vben5/apps/app-antd/src/views/_core/fallback/not-found.vue

@ -1,9 +1,51 @@
<script lang="ts" setup>
import { Fallback } from '@vben/common-ui';
import { useRouter } from 'vue-router';
import { Fallback, VbenButton } from '@vben/common-ui';
import { ArrowLeft, LogOut } from '@vben/icons';
import { $t } from '@vben/locales';
import { preferences } from '@vben/preferences';
import { Modal } from 'ant-design-vue';
import { useAuthStore } from '#/store';
defineOptions({ name: 'Fallback404Demo' });
const authStore = useAuthStore();
const { push } = useRouter();
//
function back() {
push(preferences.app.defaultHomePath);
}
// 退
function logout() {
Modal.confirm({
centered: true,
title: $t('common.logout'),
content: $t('ui.widgets.logoutTip'),
async onOk() {
await authStore.logout();
},
});
}
</script>
<template>
<Fallback status="404" />
<Fallback status="404">
<template #action>
<div class="flex gap-2">
<VbenButton size="lg" @click="back">
<ArrowLeft class="mr-2 size-4" />
{{ $t('common.backToHome') }}
</VbenButton>
<VbenButton size="lg" variant="destructive" @click="logout">
<LogOut class="mr-2 size-4" />
{{ $t('common.logout') }}
</VbenButton>
</div>
</template>
</Fallback>
</template>

25
apps/vben5/packages/@abp/account/src/api/useTokenApi.ts

@ -2,6 +2,7 @@ import type {
OAuthTokenRefreshModel,
OAuthTokenResult,
PasswordTokenRequestModel,
RevokeTokenRequest,
TokenResult,
} from '../types';
@ -75,9 +76,33 @@ export function useTokenApi() {
};
}
/**
*
* @param input
*/
async function logoutApi(input: RevokeTokenRequest): Promise<void> {
const { clientId, clientSecret } = useAppConfig(
import.meta.env,
import.meta.env.PROD,
);
return await request('/connect/revocat', {
data: {
client_id: clientId,
client_secret: clientSecret,
token: input.token,
token_type_hint: input.tokenType,
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
method: 'POST',
});
}
return {
cancel,
loginApi,
logoutApi,
refreshTokenApi,
};
}

8
apps/vben5/packages/@abp/account/src/types/token.ts

@ -28,6 +28,13 @@ interface QrCodeTokenRequest {
/** 租户Id */
tenantId?: string;
}
/** 令牌撤销请求数据类型 */
interface RevokeTokenRequest {
/** 令牌 */
token: string;
/** 令牌类型 */
tokenType?: 'access_token' | 'refresh_token';
}
/** 用户密码授权请求数据模型 */
interface PasswordTokenRequestModel {
/** 用户密码 */
@ -89,6 +96,7 @@ export type {
PasswordTokenRequestModel,
PhoneNumberTokenRequest,
QrCodeTokenRequest,
RevokeTokenRequest,
ShouldChangePasswordError,
TokenRequest,
TokenResult,

Loading…
Cancel
Save