portal commit
This commit is contained in:
@@ -1,54 +0,0 @@
|
||||
CREATE TABLE oauth2_authorization (
|
||||
id varchar(100) NOT NULL COMMENT '授权记录的唯一标识符',
|
||||
registered_client_id varchar(100) NOT NULL COMMENT '注册客户端的ID,关联到客户端注册表',
|
||||
principal_name varchar(200) NOT NULL COMMENT '授权主体的名称(通常是用户ID或用户名)',
|
||||
authorization_grant_type varchar(100) NOT NULL COMMENT '授权类型(如:authorization_code, client_credentials, refresh_token等)',
|
||||
authorized_scopes varchar(1000) DEFAULT NULL COMMENT '已授权的范围(用空格分隔的scope列表)',
|
||||
attributes blob DEFAULT NULL COMMENT '附加属性,以二进制格式存储',
|
||||
state varchar(500) DEFAULT NULL COMMENT 'OAuth2状态参数,用于防止CSRF攻击',
|
||||
authorization_code_value blob DEFAULT NULL COMMENT '授权码的值(加密存储)',
|
||||
authorization_code_issued_at timestamp NULL DEFAULT NULL COMMENT '授权码的颁发时间',
|
||||
authorization_code_expires_at timestamp NULL DEFAULT NULL COMMENT '授权码的过期时间',
|
||||
authorization_code_metadata blob DEFAULT NULL COMMENT '授权码的元数据',
|
||||
access_token_value blob DEFAULT NULL COMMENT '访问令牌的值(加密存储)',
|
||||
access_token_issued_at timestamp NULL DEFAULT NULL COMMENT '访问令牌的颁发时间',
|
||||
access_token_expires_at timestamp NULL DEFAULT NULL COMMENT '访问令牌的过期时间',
|
||||
access_token_metadata blob DEFAULT NULL COMMENT '访问令牌的元数据',
|
||||
access_token_type varchar(100) DEFAULT NULL COMMENT '访问令牌类型(如:Bearer)',
|
||||
access_token_scopes varchar(1000) DEFAULT NULL COMMENT '访问令牌的有效范围',
|
||||
oidc_id_token_value blob DEFAULT NULL COMMENT 'OIDC ID令牌的值(加密存储)',
|
||||
oidc_id_token_issued_at timestamp NULL DEFAULT NULL COMMENT 'OIDC ID令牌的颁发时间',
|
||||
oidc_id_token_expires_at timestamp NULL DEFAULT NULL COMMENT 'OIDC ID令牌的过期时间',
|
||||
oidc_id_token_metadata blob DEFAULT NULL COMMENT 'OIDC ID令牌的元数据',
|
||||
refresh_token_value blob DEFAULT NULL COMMENT '刷新令牌的值(加密存储)',
|
||||
refresh_token_issued_at timestamp NULL DEFAULT NULL COMMENT '刷新令牌的颁发时间',
|
||||
refresh_token_expires_at timestamp NULL DEFAULT NULL COMMENT '刷新令牌的过期时间',
|
||||
refresh_token_metadata blob DEFAULT NULL COMMENT '刷新令牌的元数据',
|
||||
user_code_value blob DEFAULT NULL COMMENT '设备流用户码的值(加密存储)',
|
||||
user_code_issued_at timestamp NULL DEFAULT NULL COMMENT '设备流用户码的颁发时间',
|
||||
user_code_expires_at timestamp NULL DEFAULT NULL COMMENT '设备流用户码的过期时间',
|
||||
user_code_metadata blob DEFAULT NULL COMMENT '设备流用户码的元数据',
|
||||
device_code_value blob DEFAULT NULL COMMENT '设备流设备码的值(加密存储)',
|
||||
device_code_issued_at timestamp NULL DEFAULT NULL COMMENT '设备流设备码的颁发时间',
|
||||
device_code_expires_at timestamp NULL DEFAULT NULL COMMENT '设备流设备码的过期时间',
|
||||
device_code_metadata blob DEFAULT NULL COMMENT '设备流设备码的元数据',
|
||||
PRIMARY KEY (id)
|
||||
) COMMENT='OAuth2 授权表,存储所有OAuth2和OpenID Connect的授权信息';
|
||||
|
||||
CREATE INDEX idx_registered_client_id ON oauth2_authorization(registered_client_id);
|
||||
CREATE INDEX idx_principal_name ON oauth2_authorization(principal_name);
|
||||
CREATE INDEX idx_state ON oauth2_authorization(state);
|
||||
CREATE INDEX idx_access_token_expires_at ON oauth2_authorization(access_token_expires_at);
|
||||
CREATE INDEX idx_refresh_token_expires_at ON oauth2_authorization(refresh_token_expires_at);
|
||||
CREATE INDEX idx_authorization_code_expires_at ON oauth2_authorization(authorization_code_expires_at);
|
||||
|
||||
|
||||
CREATE TABLE oauth2_authorization_consent (
|
||||
registered_client_id varchar(100) NOT NULL COMMENT '注册客户端的ID,关联到客户端注册表',
|
||||
principal_name varchar(200) NOT NULL COMMENT '授权主体的名称(通常是用户ID或用户名)',
|
||||
authorities varchar(1000) NOT NULL COMMENT '已授予的权限列表(逗号分隔的权限字符串)',
|
||||
PRIMARY KEY (registered_client_id, principal_name)
|
||||
) COMMENT='OAuth2授权同意表,存储用户对客户端的授权同意记录';
|
||||
|
||||
CREATE INDEX idx_oauth2_authorization_consent_principal_name ON oauth2_authorization_consent(principal_name);
|
||||
CREATE INDEX idx_oauth2_authorization_consent_client_id ON oauth2_authorization_consent(registered_client_id);
|
||||
@@ -4,7 +4,8 @@ VITE_APP_TITLE = IDP统一登录系统
|
||||
# 开发环境配置
|
||||
VITE_APP_ENV = 'development'
|
||||
|
||||
VITE_APP_BASE_URL=/idp-ui/
|
||||
# 开发环境
|
||||
VITE_APP_BASE_API = '/dev-api'
|
||||
VITE_APP_BASE_API = '/idp-api2'
|
||||
|
||||
VITE_APP_DEFAULT_PAGE=''
|
||||
|
||||
@@ -3,9 +3,9 @@ VITE_APP_TITLE = IDP统一登录系统
|
||||
|
||||
# 生产环境配置
|
||||
VITE_APP_ENV = 'production'
|
||||
|
||||
VITE_APP_BASE_URL=/idp-ui/
|
||||
# 生产环境
|
||||
VITE_APP_BASE_API = '/prod-api'
|
||||
VITE_APP_BASE_API = '/idp-api2'
|
||||
|
||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||
VITE_BUILD_COMPRESS = gzip
|
||||
|
||||
@@ -91,7 +91,7 @@ export function logout(): Promise<AxiosResponse<any>> {
|
||||
}
|
||||
|
||||
// 获取验证码
|
||||
export function getCodeImg(): Promise<AxiosResponse<CaptchaResponse>> {
|
||||
export function getCodeImg(): Promise<CaptchaResponse> {
|
||||
return request({
|
||||
url: '/captcha/image',
|
||||
headers: {
|
||||
|
||||
@@ -6,13 +6,11 @@ import App from './App.vue'
|
||||
import router from './router'
|
||||
import 'virtual:svg-icons-register'
|
||||
import SvgIcon from '@/components/SvgIcon'
|
||||
import elementIcons from '@/components/SvgIcon/svgicon'
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
app.use(ElementPlus)
|
||||
app.use(elementIcons)
|
||||
app.component('svg-icon', SvgIcon)
|
||||
|
||||
app.mount('#app')
|
||||
@@ -13,15 +13,15 @@ const privateKey: string = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHy
|
||||
'UP8iWi1Qw0Y='
|
||||
|
||||
// 加密
|
||||
export function encrypt(txt: string): string | false {
|
||||
export function encrypt(txt: string): string {
|
||||
const encryptor = new JSEncrypt()
|
||||
encryptor.setPublicKey(publicKey) // 设置公钥
|
||||
return encryptor.encrypt(txt) // 对数据进行加密
|
||||
return encryptor.encrypt(txt)|| "" // 对数据进行加密
|
||||
}
|
||||
|
||||
// 解密
|
||||
export function decrypt(txt: string): string | false {
|
||||
export function decrypt(txt: string): string {
|
||||
const encryptor = new JSEncrypt()
|
||||
encryptor.setPrivateKey(privateKey) // 设置私钥
|
||||
return encryptor.decrypt(txt) // 对数据进行解密
|
||||
return encryptor.decrypt(txt) || ""// 对数据进行解密
|
||||
}
|
||||
@@ -65,7 +65,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, getCurrentInstance } from 'vue'
|
||||
import { ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { getCodeImg } from '@/api/login'
|
||||
import Cookies from 'js-cookie'
|
||||
@@ -78,9 +78,9 @@ import type { FormInstance, FormRules } from 'element-plus'
|
||||
interface LoginForm {
|
||||
username: string
|
||||
password: string
|
||||
rememberMe: boolean
|
||||
code: string
|
||||
uuid: string
|
||||
rememberMe?: boolean
|
||||
code?: string
|
||||
uuid?: string
|
||||
}
|
||||
|
||||
interface CaptchaResponse {
|
||||
@@ -99,7 +99,7 @@ const footerContent = defaultSettings.footerContent
|
||||
const userStore = useUserStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { proxy } = getCurrentInstance() as { proxy: { $refs: { loginRef: FormInstance } } }
|
||||
const loginRef = ref<FormInstance>()
|
||||
|
||||
const loginForm = ref<LoginForm>({
|
||||
username: "admin",
|
||||
@@ -128,34 +128,15 @@ watch(route, (newRoute) => {
|
||||
}, { immediate: true })
|
||||
|
||||
function handleLogin(): void {
|
||||
proxy.$refs.loginRef.validate((valid: boolean) => {
|
||||
loginRef.value?.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
||||
if (loginForm.value.rememberMe) {
|
||||
Cookies.set("username", loginForm.value.username, { expires: 30 })
|
||||
Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 })
|
||||
Cookies.set("rememberMe", String(loginForm.value.rememberMe), { expires: 30 })
|
||||
} else {
|
||||
// 否则移除
|
||||
Cookies.remove("username")
|
||||
Cookies.remove("password")
|
||||
Cookies.remove("rememberMe")
|
||||
}
|
||||
handleRememberMe()
|
||||
// 调用action的登录方法
|
||||
userStore.login(loginForm.value).then(() => {
|
||||
const query: QueryParams = route.query
|
||||
const otherQueryParams = Object.keys(query).reduce((acc: QueryParams, cur: string) => {
|
||||
if (cur !== "redirect") {
|
||||
acc[cur] = query[cur]
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
if(query.redirect){
|
||||
router.push(query.redirect)
|
||||
}else{
|
||||
router.push({ path: redirect.value || "/", query: otherQueryParams })
|
||||
}
|
||||
handleRedirect(query)
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
// 重新获取验证码
|
||||
@@ -166,13 +147,37 @@ function handleLogin(): void {
|
||||
}
|
||||
})
|
||||
}
|
||||
function handleRememberMe(): void {
|
||||
if (loginForm.value.rememberMe) {
|
||||
Cookies.set("username", loginForm.value.username, { expires: 30 })
|
||||
Cookies.set("password", encrypt(loginForm.value.password), {expires: 30})
|
||||
Cookies.set("rememberMe", String(loginForm.value.rememberMe), { expires: 30 })
|
||||
} else {
|
||||
Cookies.remove("username")
|
||||
Cookies.remove("password")
|
||||
Cookies.remove("rememberMe")
|
||||
}
|
||||
}
|
||||
|
||||
function handleRedirect(query: QueryParams): void {
|
||||
if (query.redirect) {
|
||||
router.push(query.redirect);
|
||||
} else {
|
||||
router.push({
|
||||
path: redirect.value || "/",
|
||||
query: Object.keys(query).reduce((acc: Record<string, any>, cur: string) => {
|
||||
if (cur !== "redirect") acc[cur] = query[cur];
|
||||
return acc;
|
||||
}, {})
|
||||
});
|
||||
}
|
||||
}
|
||||
function getCode(): void {
|
||||
getCodeImg().then((res: CaptchaResponse) => {
|
||||
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled
|
||||
if (captchaEnabled.value && res.img && res.uuid) {
|
||||
codeUrl.value = "data:image/gif;base64," + res.img
|
||||
loginForm.value.uuid = res.uuid
|
||||
getCodeImg().then((data: CaptchaResponse) => {
|
||||
captchaEnabled.value = data.captchaEnabled === undefined ? true : data.captchaEnabled
|
||||
if (captchaEnabled.value && data.img && data.uuid) {
|
||||
codeUrl.value = "data:image/gif;base64," + data.img
|
||||
loginForm.value.uuid = data.uuid
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -184,7 +189,7 @@ function getCookie(): void {
|
||||
loginForm.value = {
|
||||
username: username === undefined ? loginForm.value.username : username,
|
||||
password: password === undefined ? loginForm.value.password : decrypt(password),
|
||||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
|
||||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,6 @@
|
||||
"~/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue","vite/**/*.ts"],
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
@@ -12,7 +12,7 @@ export default defineConfig(({ mode, command }) => {
|
||||
return {
|
||||
// 部署生产环境和开发环境下的URL。
|
||||
// 默认情况下,vite 会假设你的应用是被部署在一个域名的根路径上
|
||||
base: VITE_APP_ENV === 'production' ? '/' : '/',
|
||||
base: VITE_APP_ENV === 'production' ? env?.VITE_APP_BASE_URL || '/idp/' : env?.VITE_APP_BASE_URL || '/',
|
||||
plugins: createVitePlugins(env, command === 'build'),
|
||||
resolve: {
|
||||
// https://cn.vitejs.dev/config/#resolve-alias
|
||||
|
||||
Reference in New Issue
Block a user