@@ -0,0 +1,24 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
export function loginOptions() {
|
||||||
|
return request({
|
||||||
|
url: '/login-options',
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function oidcAuth (data) {
|
||||||
|
return request({
|
||||||
|
url: '/oidc/auth',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function oidcQuery(params){
|
||||||
|
return request({
|
||||||
|
url: '/oidc/auth-query',
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
})
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
+55
-13
@@ -1,8 +1,9 @@
|
|||||||
import { defineStore, acceptHMRUpdate } from 'pinia'
|
import { defineStore, acceptHMRUpdate } from 'pinia'
|
||||||
import { current, login } from '@/api/user'
|
import { current, login } from '@/api/user'
|
||||||
import { setToken, removeToken } from '@/utils/auth'
|
import { setToken, removeToken, setCode, removeCode } from '@/utils/auth'
|
||||||
import { useRouteStore } from '@/store/router'
|
import { useRouteStore } from '@/store/router'
|
||||||
import { useAppStore } from '@/store/app'
|
import { useAppStore } from '@/store/app'
|
||||||
|
import { oidcAuth, oidcQuery } from '@/api/login';
|
||||||
|
|
||||||
export const useUserStore = defineStore({
|
export const useUserStore = defineStore({
|
||||||
id: 'user',
|
id: 'user',
|
||||||
@@ -16,34 +17,40 @@ export const useUserStore = defineStore({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
logout () {
|
logout() {
|
||||||
removeToken()
|
removeToken()
|
||||||
|
removeCode()
|
||||||
this.$patch({
|
this.$patch({
|
||||||
name: '',
|
name: '',
|
||||||
role: {},
|
role: {},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async login (form) {
|
saveUserData(userData) {
|
||||||
|
// useAppStore().getAppConfig()
|
||||||
|
setToken(userData.token)
|
||||||
|
//
|
||||||
|
localStorage.setItem('user_info', JSON.stringify({ name: userData.username }))
|
||||||
|
this.$patch({
|
||||||
|
...userData,
|
||||||
|
})
|
||||||
|
if (userData.route_names && userData.route_names.length) {
|
||||||
|
useRouteStore().addRoutes(userData.route_names)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async login(form) {
|
||||||
const res = await login(form).catch(_ => false)
|
const res = await login(form).catch(_ => false)
|
||||||
if (res) {
|
if (res) {
|
||||||
useAppStore().getAppConfig()
|
useAppStore().getAppConfig()
|
||||||
const userData = res.data
|
const userData = res.data
|
||||||
setToken(userData.token)
|
this.saveUserData(userData)
|
||||||
//
|
|
||||||
localStorage.setItem('user_info', JSON.stringify({ name: userData.username }))
|
|
||||||
this.$patch({
|
|
||||||
...userData,
|
|
||||||
})
|
|
||||||
if (userData.route_names && userData.route_names.length) {
|
|
||||||
useRouteStore().addRoutes(userData.route_names)
|
|
||||||
}
|
|
||||||
return userData
|
return userData
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async info () {
|
async info() {
|
||||||
const res = await current().catch(_ => false)
|
const res = await current().catch(_ => false)
|
||||||
if (res) {
|
if (res) {
|
||||||
useAppStore().getAppConfig()
|
useAppStore().getAppConfig()
|
||||||
@@ -57,6 +64,41 @@ export const useUserStore = defineStore({
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
|
async oidc(provider, platform, browser) {
|
||||||
|
// oidc data need to be implement
|
||||||
|
const data = {
|
||||||
|
deviceInfo: {
|
||||||
|
name: navigator.userAgent, // 使用浏览器的 User-Agent 作为设备名
|
||||||
|
os: platform, // 获取操作系统信息
|
||||||
|
type: 'webadmin', // any vaule
|
||||||
|
},
|
||||||
|
id: `${platform}-${browser}`,
|
||||||
|
op: provider, // 传入的 provider
|
||||||
|
uuid: crypto.randomUUID(), // 自动生成 UUID
|
||||||
|
};
|
||||||
|
const res = await oidcAuth(data).catch(_ => false)
|
||||||
|
if (res) {
|
||||||
|
const { code, url } = res.data
|
||||||
|
setCode(code)
|
||||||
|
if (provider == 'webauth') {
|
||||||
|
window.open(url)
|
||||||
|
} else {
|
||||||
|
window.location.href = url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async query(code) {
|
||||||
|
const params = { "code": code, "uuid": crypto.randomUUID(), "Id": "999" }
|
||||||
|
const res = await oidcQuery(params).catch(_ => false)
|
||||||
|
if (res) {
|
||||||
|
removeCode()
|
||||||
|
useAppStore().getAppConfig()
|
||||||
|
const userData = res.data
|
||||||
|
this.saveUserData(userData)
|
||||||
|
return userData
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
const TokenKey = 'access_token'
|
const TokenKey = 'access_token'
|
||||||
|
const OidcCode = 'oidc_code'
|
||||||
|
const OidcCodeExpiry = 'oidc_code_expiry';
|
||||||
|
|
||||||
export function getToken () {
|
export function getToken () {
|
||||||
return localStorage.getItem(TokenKey)
|
return localStorage.getItem(TokenKey)
|
||||||
@@ -11,3 +13,31 @@ export function setToken (token) {
|
|||||||
export function removeToken () {
|
export function removeToken () {
|
||||||
return localStorage.removeItem(TokenKey)
|
return localStorage.removeItem(TokenKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置 code,并存储当前时间戳(单位:毫秒)
|
||||||
|
export function setCode(code) {
|
||||||
|
const now = Date.now(); // 当前时间戳(毫秒)
|
||||||
|
const expiry = now + 60 * 1000; // 60 秒后过期
|
||||||
|
|
||||||
|
localStorage.setItem(OidcCode, code); // 存储 code
|
||||||
|
localStorage.setItem(OidcCodeExpiry, expiry); // 存储过期时间戳
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取 code,如果已过期则删除并返回 null
|
||||||
|
export function getCode() {
|
||||||
|
const expiry = localStorage.getItem(OidcCodeExpiry); // 获取过期时间戳
|
||||||
|
const now = Date.now(); // 当前时间戳
|
||||||
|
|
||||||
|
if (expiry && now > parseInt(expiry)) {
|
||||||
|
// 如果已过期,删除 code 和过期时间
|
||||||
|
removeCode();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return localStorage.getItem(OidcCode); // 返回 code(如果未过期)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除 code 和过期时间
|
||||||
|
export function removeCode() {
|
||||||
|
localStorage.removeItem(OidcCode);
|
||||||
|
localStorage.removeItem(OidcCodeExpiry);
|
||||||
|
}
|
||||||
@@ -427,5 +427,9 @@
|
|||||||
},
|
},
|
||||||
"LastOnlineIp": {
|
"LastOnlineIp": {
|
||||||
"One": "最后在线IP"
|
"One": "最后在线IP"
|
||||||
|
},
|
||||||
|
"or login in with" :
|
||||||
|
{
|
||||||
|
"One": "或使用以下登陆"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ service.interceptors.response.use(
|
|||||||
response => {
|
response => {
|
||||||
const res = response.data
|
const res = response.data
|
||||||
|
|
||||||
|
// for the endpoint /login-options
|
||||||
|
// I'm not sure if this is a good idea
|
||||||
|
if (Array.isArray(res)) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
// if the custom code is not 20000, it is judged as an error.
|
// if the custom code is not 20000, it is judged as an error.
|
||||||
if (res.code !== 0) {
|
if (res.code !== 0) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
|
|||||||
+225
-65
@@ -1,98 +1,258 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login">
|
<div class="login-container">
|
||||||
<el-card class="login-card">
|
<div class="login-card">
|
||||||
<h1>{{ T('Login') }}</h1>
|
<img src="@/assets/logo.png" alt="logo" class="login-logo" />
|
||||||
<el-form label-width="100px">
|
|
||||||
<el-form-item :label=" T('Username') ">
|
<el-form label-position="top" class="login-form">
|
||||||
<el-input v-model="form.username"></el-input>
|
<el-form-item :label="T('Username')">
|
||||||
|
<el-input v-model="form.username" class="login-input"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label=" T('Password') ">
|
|
||||||
<el-input v-model="form.password" type="password" @keyup.enter.native="login" show-password></el-input>
|
<el-form-item :label="T('Password')">
|
||||||
|
<el-input v-model="form.password" type="password" @keyup.enter.native="login" show-password
|
||||||
|
class="login-input"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button @click="login" type="primary">{{ T('Login') }}</el-button>
|
<el-button @click="login" type="primary" class="login-button">{{ T('Login') }}</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
|
||||||
|
<div class="divider" v-if="options.length > 0">
|
||||||
|
<span>{{ T('or login in with') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="oidc-options">
|
||||||
|
<div v-for="(option, index) in options" :key="index" class="oidc-option">
|
||||||
|
<el-button @click="handleOIDCLogin(option.name)" class="oidc-btn">
|
||||||
|
<img :src="getProviderImage(option.name)" alt="provider" class="oidc-icon" />
|
||||||
|
{{ T(option.name) }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineComponent, reactive } from 'vue'
|
import { reactive, onMounted, ref } from 'vue';
|
||||||
import { useUserStore } from '@/store/user'
|
import { useUserStore } from '@/store/user'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus';
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { T } from '@/utils/i18n';
|
||||||
import { T } from '@/utils/i18n'
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import { loginOptions, oidcAuth, oidcQuery } from '@/api/login';
|
||||||
|
import { getCode, removeCode } from '@/utils/auth'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const oauthInfo = ref({})
|
||||||
const route = useRoute()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const options = reactive([]); // 存储 OIDC 登录选项
|
||||||
|
|
||||||
let platform = window.navigator.platform
|
let platform = window.navigator.platform
|
||||||
if (navigator.platform.indexOf('Mac') === 0) {
|
if (navigator.platform.indexOf('Mac') === 0) {
|
||||||
platform = 'mac'
|
platform = 'mac'
|
||||||
} else if (navigator.platform.indexOf('Win') === 0) {
|
} else if (navigator.platform.indexOf('Win') === 0) {
|
||||||
platform = 'windows'
|
platform = 'windows'
|
||||||
} else if (navigator.platform.indexOf('Linux armv') === 0) {
|
} else if (navigator.platform.indexOf('Linux armv') === 0) {
|
||||||
platform = 'android'
|
platform = 'android'
|
||||||
} else if (navigator.platform.indexOf('Linux') === 0) {
|
} else if (navigator.platform.indexOf('Linux') === 0) {
|
||||||
platform = 'linux'
|
platform = 'linux'
|
||||||
|
}
|
||||||
|
const userAgent = navigator.userAgent;
|
||||||
|
let browser = 'Unknown Browser';
|
||||||
|
if (/chrome|crios/i.test(userAgent)) browser = 'Chrome';
|
||||||
|
else if (/firefox|fxios/i.test(userAgent)) browser = 'Firefox';
|
||||||
|
else if (/safari/i.test(userAgent) && !/chrome/i.test(userAgent)) browser = 'Safari';
|
||||||
|
else if (/edg/i.test(userAgent)) browser = 'Edge';
|
||||||
|
|
||||||
|
const form = reactive({
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
platform: platform,
|
||||||
|
})
|
||||||
|
|
||||||
|
const redirect = route.query?.redirect
|
||||||
|
const login = async () => {
|
||||||
|
const res = await userStore.login(form)
|
||||||
|
if (res) {
|
||||||
|
ElMessage.success(T('LoginSuccess'))
|
||||||
|
router.push({ path: redirect || '/', replace: true })
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const form = reactive({
|
const handleOIDCLogin = (provider) => {
|
||||||
username: '',
|
userStore.oidc(provider, platform, browser)
|
||||||
password: '',
|
};
|
||||||
platform: platform,
|
|
||||||
})
|
import googleImage from '@/assets/google.png';
|
||||||
const redirect = route.query?.redirect
|
import githubImage from '@/assets/github.png';
|
||||||
const login = async () => {
|
import oidcImage from '@/assets/oidc.png';
|
||||||
const res = await userStore.login(form)
|
import webauthImage from '@/assets/webauth.png';
|
||||||
|
import defaultImage from '@/assets/oidc.png';
|
||||||
|
|
||||||
|
const providerImageMap = {
|
||||||
|
google: googleImage,
|
||||||
|
github: githubImage,
|
||||||
|
oidc: oidcImage,
|
||||||
|
webauth: webauthImage,
|
||||||
|
default: defaultImage,
|
||||||
|
};
|
||||||
|
|
||||||
|
const getProviderImage = (provider) => {
|
||||||
|
return providerImageMap[provider] || providerImageMap.default;
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadLoginOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await loginOptions().catch(() => []);
|
||||||
|
if (!Array.isArray(res) || !res.length) return console.warn('No valid response received');
|
||||||
|
|
||||||
|
const jsonPart = res[0].split('/')[1];
|
||||||
|
if (!jsonPart) return console.error('Invalid input string:', res[0]);
|
||||||
|
|
||||||
|
// const ops = JSON.parse(jsonPart).map(option => ({ name: option.name }));
|
||||||
|
// 不确定怎么处理webauth,不显示
|
||||||
|
// 解析 JSON,并过滤掉 "webauth" 类型的选项
|
||||||
|
const ops = JSON.parse(jsonPart)
|
||||||
|
.filter(option => option.name !== "webauth") // 排除 "webauth" 类型的选项
|
||||||
|
.map(option => ({ name: option.name })); // 创建新的对象数组
|
||||||
|
if (!ops.length) return;
|
||||||
|
|
||||||
|
options.push(...ops);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading login options:', error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const code = getCode();
|
||||||
|
if (code) {
|
||||||
|
// 如果code存在,进行query获取user info
|
||||||
|
const res = await userStore.query(code)
|
||||||
if (res) {
|
if (res) {
|
||||||
|
// 删除code,确保跳转之前对code进行清楚
|
||||||
|
removeCode()
|
||||||
ElMessage.success(T('LoginSuccess'))
|
ElMessage.success(T('LoginSuccess'))
|
||||||
router.push({ path: redirect || '/', replace: true })
|
router.push({ path: redirect || '/', replace: true })
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// 如果code不存在, 现实登陆页面
|
||||||
|
loadLoginOptions(); // 组件挂载后调用登录选项加载函数
|
||||||
}
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.login {
|
.login-container {
|
||||||
width: 100vw;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background-color: #2d3a4b;
|
background-color: #2d3a4b;
|
||||||
padding-top: 25vh;
|
padding: 20px;
|
||||||
box-sizing: border-box;
|
}
|
||||||
|
|
||||||
.tips {
|
.login-card {
|
||||||
font-size: 12px;
|
width: 360px;
|
||||||
color: #fff;
|
background-color: #283342;
|
||||||
margin-left: 60px;
|
padding: 40px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-button {
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #888;
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
flex: 1;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-card {
|
&::before {
|
||||||
max-width: 500px;
|
margin-right: 10px;
|
||||||
background-color: #283342;
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.oidc-options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oidc-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: black;
|
||||||
|
font-size: 14px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.oidc-icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-logo {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
margin: 0 auto 20px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
::v-deep(.el-form-item__label) {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border: none;
|
}
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
.el-form-item {
|
.el-input {
|
||||||
|
::v-deep(.el-input__wrapper) {
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
::v-deep(.el-form-item__label) {
|
::v-deep(input) {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
|
||||||
|
|
||||||
.el-input {
|
|
||||||
|
|
||||||
::v-deep(.el-input__wrapper) {
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
::v-deep(input) {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
+14
-13
@@ -11,7 +11,7 @@
|
|||||||
<el-card class="list-body" shadow="hover">
|
<el-card class="list-body" shadow="hover">
|
||||||
<el-table :data="listRes.list" v-loading="listRes.loading" border>
|
<el-table :data="listRes.list" v-loading="listRes.loading" border>
|
||||||
<el-table-column prop="id" label="id" align="center"/>
|
<el-table-column prop="id" label="id" align="center"/>
|
||||||
<el-table-column prop="op" :label="T('Op')" align="center"/>
|
<el-table-column prop="op" :label="T('Type')" align="center"/>
|
||||||
<el-table-column prop="auto_register" :label="T('AutoRegister')" align="center"/>
|
<el-table-column prop="auto_register" :label="T('AutoRegister')" align="center"/>
|
||||||
<el-table-column prop="created_at" :label="T('CreatedAt')" align="center"/>
|
<el-table-column prop="created_at" :label="T('CreatedAt')" align="center"/>
|
||||||
<el-table-column prop="updated_at" :label="T('UpdatedAt')" align="center"/>
|
<el-table-column prop="updated_at" :label="T('UpdatedAt')" align="center"/>
|
||||||
@@ -34,8 +34,18 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
<el-dialog v-model="formVisible" :title="!formData.id?T('Create') :T('Update')" width="800">
|
<el-dialog v-model="formVisible" :title="!formData.id?T('Create') :T('Update')" width="800">
|
||||||
<el-form class="dialog-form" ref="form" :model="formData" :rules="rules" label-width="120px">
|
<el-form class="dialog-form" ref="form" :model="formData" :rules="rules" label-width="120px">
|
||||||
<el-form-item label="Issuer" prop="issuer">
|
<el-form-item label="Type" prop="op">
|
||||||
<el-input v-model="formData.issuer" :placeholder="formData.op === 'oidc' ? 'Required when OIDC is selected' : 'Not required unless OIDC is selected'"></el-input>
|
<el-radio-group v-model="formData.op" :disabled="!!formData.id">
|
||||||
|
<el-radio v-for="item in ops" :key="item.value" :value="item.value" style="display: block">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="formData.op === 'oidc'" label="Issuer" prop="issuer">
|
||||||
|
<el-input v-model="formData.issuer" placeholder="Check your IdP docs, without '/.well-known/openid-configuration'"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-show="formData.op === 'oidc'" label="Scopes" prop="scopes">
|
||||||
|
<el-input v-model="formData.scopes" placeholder= "Optional, default is 'openid,profile,email'"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="ClientId" prop="client_id">
|
<el-form-item label="ClientId" prop="client_id">
|
||||||
<el-input v-model="formData.client_id"></el-input>
|
<el-input v-model="formData.client_id"></el-input>
|
||||||
@@ -46,16 +56,6 @@
|
|||||||
<el-form-item label="RedirectUrl" prop="redirect_url">
|
<el-form-item label="RedirectUrl" prop="redirect_url">
|
||||||
<el-input v-model="formData.redirect_url"></el-input>
|
<el-input v-model="formData.redirect_url"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Scopes" prop="scopes">
|
|
||||||
<el-input v-model="formData.scopes" :placeholder="formData.op === 'oidc' ? 'Optional when OIDC is selected, default is openid,profile,email' : 'Not required unless OIDC is selected'"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="op" prop="op">
|
|
||||||
<el-radio-group v-model="formData.op" :disabled="!!formData.id">
|
|
||||||
<el-radio v-for="item in ops" :key="item.value" :value="item.value" style="display: block">
|
|
||||||
{{ item.label }}
|
|
||||||
</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="T('AutoRegister')" prop="auto_register">
|
<el-form-item :label="T('AutoRegister')" prop="auto_register">
|
||||||
<el-switch v-model="formData.auto_register"
|
<el-switch v-model="formData.auto_register"
|
||||||
:active-value="true"
|
:active-value="true"
|
||||||
@@ -146,6 +146,7 @@
|
|||||||
client_secret: [{ required: true, message: T('ParamRequired', { param: 'client_secret' }), trigger: 'blur' }],
|
client_secret: [{ required: true, message: T('ParamRequired', { param: 'client_secret' }), trigger: 'blur' }],
|
||||||
redirect_url: [{ required: true, message: T('ParamRequired', { param: 'redirect_url' }), trigger: 'blur' }],
|
redirect_url: [{ required: true, message: T('ParamRequired', { param: 'redirect_url' }), trigger: 'blur' }],
|
||||||
op: [{ required: true, message: T('ParamRequired', { param: 'op' }), trigger: 'blur' }],
|
op: [{ required: true, message: T('ParamRequired', { param: 'op' }), trigger: 'blur' }],
|
||||||
|
issuer: [{ required: true, message: T('ParamRequired', { param: 'issuer' }), trigger: 'blur' }],
|
||||||
}
|
}
|
||||||
const toEdit = (row) => {
|
const toEdit = (row) => {
|
||||||
formVisible.value = true
|
formVisible.value = true
|
||||||
|
|||||||
Reference in New Issue
Block a user