49 changed files with 1827 additions and 2159 deletions
@ -1,13 +1,22 @@ |
|||
using Volo.Abp.Application.Services; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
using Volo.Abp.Authorization.Permissions; |
|||
using Volo.Abp.IdentityServer.Localization; |
|||
|
|||
namespace LINGYUN.Abp.IdentityServer |
|||
{ |
|||
public abstract class AbpIdentityServerAppServiceBase : ApplicationService |
|||
{ |
|||
private IPermissionChecker _permissionChecker; |
|||
protected IPermissionChecker PermissionChecker => LazyGetRequiredService(ref _permissionChecker); |
|||
protected AbpIdentityServerAppServiceBase() |
|||
{ |
|||
LocalizationResource = typeof(AbpIdentityServerResource); |
|||
} |
|||
|
|||
protected virtual async Task<bool> IsGrantAsync(string policy) |
|||
{ |
|||
return await PermissionChecker.IsGrantedAsync(policy); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,11 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.IdentityServer.ApiResources |
|||
{ |
|||
public interface IApiResourceRepository : Volo.Abp.IdentityServer.ApiResources.IApiResourceRepository |
|||
{ |
|||
Task<List<string>> GetNamesAsync(CancellationToken cancellationToken = default); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.IdentityServer.IdentityResources |
|||
{ |
|||
public interface IIdentityResourceRepository : Volo.Abp.IdentityServer.IdentityResources.IIdentityResourceRepository |
|||
{ |
|||
Task<List<string>> GetNamesAsync(CancellationToken cancellationToken = default); |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.IdentityServer.ApiResources; |
|||
using Volo.Abp.IdentityServer.EntityFrameworkCore; |
|||
|
|||
namespace LINGYUN.Abp.IdentityServer.ApiResources |
|||
{ |
|||
[Dependency(ServiceLifetime.Transient)] |
|||
[ExposeServices( |
|||
typeof(IApiResourceRepository), |
|||
typeof(ApiResourceRepository), |
|||
typeof(Volo.Abp.IdentityServer.ApiResources.IApiResourceRepository))] |
|||
public class EfCoreApiResourceRepository : ApiResourceRepository, IApiResourceRepository |
|||
{ |
|||
public EfCoreApiResourceRepository( |
|||
IDbContextProvider<IIdentityServerDbContext> dbContextProvider) |
|||
: base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public virtual async Task<List<string>> GetNamesAsync(CancellationToken cancellationToken = default) |
|||
{ |
|||
return await DbSet |
|||
.Select(x => x.Name) |
|||
.Distinct() |
|||
.ToListAsync(GetCancellationToken(cancellationToken)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.IdentityServer.EntityFrameworkCore; |
|||
using Volo.Abp.IdentityServer.IdentityResources; |
|||
|
|||
namespace LINGYUN.Abp.IdentityServer.IdentityResources |
|||
{ |
|||
[Dependency(ServiceLifetime.Transient)] |
|||
[ExposeServices( |
|||
typeof(IIdentityResourceRepository), |
|||
typeof(IdentityResourceRepository), |
|||
typeof(Volo.Abp.IdentityServer.IdentityResources.IIdentityResourceRepository))] |
|||
public class EfCoreIdentityResourceRepository : IdentityResourceRepository, IIdentityResourceRepository |
|||
{ |
|||
public EfCoreIdentityResourceRepository( |
|||
IDbContextProvider<IIdentityServerDbContext> dbContextProvider) |
|||
: base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public virtual async Task<List<string>> GetNamesAsync(CancellationToken cancellationToken = default) |
|||
{ |
|||
return await DbSet |
|||
.Select(x => x.Name) |
|||
.Distinct() |
|||
.ToListAsync(GetCancellationToken(cancellationToken)); |
|||
} |
|||
} |
|||
} |
|||
Binary file not shown.
@ -0,0 +1,36 @@ |
|||
import ApiService from './serviceBase' |
|||
|
|||
const openIdConfigurationUrl = '/.well-known/openid-configuration' |
|||
|
|||
export default class IdentityServer4Service { |
|||
public static getOpenIdConfiguration() { |
|||
return ApiService.Get<OpenIdConfiguration>(openIdConfigurationUrl) |
|||
} |
|||
} |
|||
|
|||
export class OpenIdConfiguration { |
|||
issuer!: string |
|||
jwks_uri!: string |
|||
authorization_endpoint!: string |
|||
token_endpoint!: string |
|||
userinfo_endpoint!: string |
|||
end_session_endpoint!: string |
|||
check_session_iframe!: string |
|||
revocation_endpoint!: string |
|||
introspection_endpoint!: string |
|||
device_authorization_endpoint!: string |
|||
frontchannel_logout_supported!: boolean |
|||
frontchannel_logout_session_supported!: boolean |
|||
backchannel_logout_supported!: boolean |
|||
backchannel_logout_session_supported!: boolean |
|||
scopes_supported = new Array<string>() |
|||
claims_supported = new Array<string>() |
|||
grant_types_supported = new Array<string>() |
|||
response_types_supported = new Array<string>() |
|||
response_modes_supported = new Array<string>() |
|||
token_endpoint_auth_methods_supported = new Array<string>() |
|||
id_token_signing_alg_values_supported = new Array<string>() |
|||
subject_types_supported = new Array<string>() |
|||
code_challenge_methods_supported = new Array<string>() |
|||
request_parameter_supported!: boolean |
|||
} |
|||
@ -1,250 +0,0 @@ |
|||
<template> |
|||
<el-form |
|||
ref="apiResourceSecretEditForm" |
|||
:model="apiResourceSecret" |
|||
label-width="80px" |
|||
:rules="apiResourceSecretRules" |
|||
> |
|||
<el-row> |
|||
<el-col :span="12"> |
|||
<el-form-item |
|||
prop="type" |
|||
:label="$t('AbpIdentityServer.Secret:Type')" |
|||
> |
|||
<el-select |
|||
v-model="apiResourceSecret.type" |
|||
class="full-select" |
|||
:placeholder="$t('pleaseSelectBy', {key: $t('AbpIdentityServer.Secret:Type')})" |
|||
> |
|||
<el-option |
|||
key="JWK" |
|||
label="JsonWebKey" |
|||
value="JWK" |
|||
/> |
|||
<el-option |
|||
key="SharedSecret" |
|||
label="SharedSecret" |
|||
value="SharedSecret" |
|||
/> |
|||
<el-option |
|||
key="X509Name" |
|||
label="X509CertificateName" |
|||
value="X509Name" |
|||
/> |
|||
<el-option |
|||
key="X509CertificateBase64" |
|||
label="X509CertificateBase64" |
|||
value="X509CertificateBase64" |
|||
/> |
|||
<el-option |
|||
key="X509Thumbprint" |
|||
label="X509CertificateThumbprint" |
|||
value="X509Thumbprint" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
</el-col> |
|||
<el-col :span="12"> |
|||
<el-form-item |
|||
prop="hashType" |
|||
:label="$t('AbpIdentityServer.Secret:HashType')" |
|||
> |
|||
<el-popover |
|||
ref="popHashType" |
|||
placement="top-start" |
|||
trigger="hover" |
|||
:content="$t('identityServer.hashOnlySharedSecret')" |
|||
/> |
|||
<el-select |
|||
v-model="apiResourceSecret.hashType" |
|||
v-popover:popHashType |
|||
:disabled="apiResourceSecret.type !== 'SharedSecret'" |
|||
class="full-select" |
|||
:placeholder="$t('pleaseSelectBy', {key: $t('AbpIdentityServer.Secret:HashType')})" |
|||
> |
|||
<el-option |
|||
:key="0" |
|||
label="Sha256" |
|||
:value="0" |
|||
/> |
|||
<el-option |
|||
:key="1" |
|||
label="Sha512" |
|||
:value="1" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
</el-col> |
|||
</el-row> |
|||
<el-form-item |
|||
prop="value" |
|||
:label="$t('AbpIdentityServer.Secret:Value')" |
|||
> |
|||
<el-input |
|||
v-model="apiResourceSecret.value" |
|||
:placeholder="$t('pleaseInputBy', {key: $t('AbpIdentityServer.Secret:Value')})" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="description" |
|||
:label="$t('AbpIdentityServer.Description')" |
|||
> |
|||
<el-input |
|||
v-model="apiResourceSecret.description" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="expiration" |
|||
:label="$t('AbpIdentityServer.Expiration')" |
|||
> |
|||
<el-date-picker |
|||
v-model="apiResourceSecret.expiration" |
|||
class="full-select" |
|||
type="datetime" |
|||
/> |
|||
</el-form-item> |
|||
|
|||
<el-form-item |
|||
style="text-align: center;" |
|||
label-width="0px" |
|||
> |
|||
<el-button |
|||
type="primary" |
|||
style="width:180px" |
|||
@click="onSave" |
|||
> |
|||
{{ $t('AbpIdentityServer.Secret:New') }} |
|||
</el-button> |
|||
</el-form-item> |
|||
<el-table |
|||
row-key="value" |
|||
:data="apiResourceSecrets" |
|||
border |
|||
fit |
|||
highlight-current-row |
|||
style="width: 100%;" |
|||
> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Secret:Type')" |
|||
prop="type" |
|||
sortable |
|||
width="170px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.type }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Secret:Value')" |
|||
prop="value" |
|||
sortable |
|||
width="200px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.value }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Description')" |
|||
prop="description" |
|||
width="120px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.description }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Expiration')" |
|||
prop="expiration" |
|||
width="170px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.expiration | dateTimeFilter }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
align="center" |
|||
width="80px" |
|||
fixed="right" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<el-button |
|||
:disabled="!checkPermission(['IdentityServer.ApiResources.Secrets.Delete'])" |
|||
type="danger" |
|||
icon="el-icon-delete" |
|||
size="mini" |
|||
@click="handleDeleteApiSecret(row.type, row.value)" |
|||
/> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
</el-form> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { ApiSecretCreateOrUpdate, ApiSecret } from '@/api/api-resources' |
|||
import { Component, Vue, Prop } from 'vue-property-decorator' |
|||
import { dateFormat } from '@/utils/index' |
|||
import { checkPermission } from '@/utils/permission' |
|||
import { Form } from 'element-ui' |
|||
|
|||
@Component({ |
|||
name: 'ApiResourceSecretEditForm', |
|||
filters: { |
|||
dateTimeFilter(datetime: string) { |
|||
if (datetime) { |
|||
const date = new Date(datetime) |
|||
return dateFormat(date, 'YYYY-mm-dd HH:MM:SS') |
|||
} |
|||
return '' |
|||
} |
|||
}, |
|||
methods: { |
|||
checkPermission |
|||
} |
|||
}) |
|||
export default class ApiResourceSecretEditForm extends Vue { |
|||
@Prop({ default: () => { return new Array<ApiSecret>() } }) |
|||
private apiResourceSecrets!: ApiSecret[] |
|||
|
|||
private apiResourceSecret = new ApiSecretCreateOrUpdate() |
|||
private apiResourceSecretRules = { |
|||
type: [ |
|||
{ required: true, message: this.l('pleaseSelectBy', { key: this.l('AbpIdentityServer.Secret:Type') }), trigger: 'blur' } |
|||
], |
|||
value: [ |
|||
{ required: true, message: this.l('pleaseInputBy', { key: this.l('AbpIdentityServer.Secret:Value') }), trigger: 'blur' } |
|||
] |
|||
} |
|||
|
|||
private onSave() { |
|||
const apiResourceSecretEditForm = this.$refs.apiResourceSecretEditForm as Form |
|||
apiResourceSecretEditForm.validate(valid => { |
|||
if (valid) { |
|||
this.$emit('apiResourceSecretCreated', |
|||
this.apiResourceSecret.hashType, this.apiResourceSecret.type, this.apiResourceSecret.value, |
|||
this.apiResourceSecret.description, this.apiResourceSecret.expiration) |
|||
apiResourceSecretEditForm.resetFields() |
|||
} |
|||
}) |
|||
} |
|||
|
|||
private handleDeleteApiSecret(type: string, value: string) { |
|||
this.$emit('apiResourceSecretDeleted', type, value) |
|||
} |
|||
|
|||
private l(name: string, values?: any[] | { [key: string]: any }) { |
|||
return this.$t(name, values).toString() |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.full-select { |
|||
width: 100%; |
|||
} |
|||
</style> |
|||
@ -1,147 +0,0 @@ |
|||
<template> |
|||
<el-dialog |
|||
v-el-draggable-dialog |
|||
width="800px" |
|||
:visible="showDialog" |
|||
:title="$t('identityServer.clientPermission')" |
|||
custom-class="modal-form" |
|||
:show-close="false" |
|||
@close="onFormClosed" |
|||
> |
|||
<el-form |
|||
ref="formClient" |
|||
label-width="100px" |
|||
:model="clientPermission" |
|||
label-position="top" |
|||
> |
|||
<el-form-item v-if="hasLoadPermission"> |
|||
<permission-tree |
|||
ref="PermissionTree" |
|||
:expanded="false" |
|||
:readonly="!checkPermission(['IdentityServer.Clients.ManagePermissions'])" |
|||
:permission="clientPermission" |
|||
@onPermissionChanged="onPermissionChanged" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button |
|||
class="cancel" |
|||
style="width:100px" |
|||
@click="onCancel" |
|||
> |
|||
{{ $t('table.cancel') }} |
|||
</el-button> |
|||
<el-button |
|||
class="confirm" |
|||
type="primary" |
|||
style="width:100px" |
|||
:disabled="!checkPermission(['IdentityServer.Clients.ManagePermissions'])" |
|||
@click="onSaveClientPemissions" |
|||
> |
|||
{{ $t('table.confirm') }} |
|||
</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { IPermission } from '@/api/types' |
|||
import { checkPermission } from '@/utils/permission' |
|||
import PermissionTree from '@/components/PermissionTree/index.vue' |
|||
import { Component, Vue, Prop, Watch } from 'vue-property-decorator' |
|||
import PermissionService, { PermissionDto, UpdatePermissionsDto } from '@/api/permission' |
|||
|
|||
@Component({ |
|||
name: 'ClientPermissionEditForm', |
|||
components: { |
|||
PermissionTree |
|||
}, |
|||
methods: { |
|||
checkPermission |
|||
} |
|||
}) |
|||
export default class extends Vue { |
|||
@Prop({ default: false }) |
|||
private showDialog!: boolean |
|||
|
|||
/** 客户端标识 */ |
|||
@Prop({ default: '' }) |
|||
private clientId!: string |
|||
|
|||
/** 客户端权限 */ |
|||
private clientPermission: PermissionDto |
|||
/** 是否已加载权限 */ |
|||
private hasLoadPermission: boolean |
|||
/** 客户端权限已变更 */ |
|||
private clientPermissionChanged: boolean |
|||
/** 变更客户端权限数据 */ |
|||
private editClientPermissions: IPermission[] |
|||
|
|||
constructor() { |
|||
super() |
|||
this.hasLoadPermission = false |
|||
this.clientPermissionChanged = false |
|||
this.clientPermission = new PermissionDto() |
|||
this.editClientPermissions = new Array<IPermission>() |
|||
} |
|||
|
|||
/** 监听客户端标识变更事件,刷新客户端权限数据 */ |
|||
@Watch('clientId') |
|||
private onClientIdChanged() { |
|||
this.handledGetClientPermissions() |
|||
} |
|||
|
|||
mounted() { |
|||
this.handledGetClientPermissions() |
|||
} |
|||
|
|||
private handledGetClientPermissions() { |
|||
if (this.showDialog && this.clientId) { |
|||
PermissionService.getPermissionsByKey('C', this.clientId).then(permission => { |
|||
this.clientPermission = permission |
|||
this.hasLoadPermission = true |
|||
}) |
|||
} |
|||
} |
|||
|
|||
/** 客户端权限树变更事件 |
|||
* @param permissions 变更权限数据 |
|||
*/ |
|||
private onPermissionChanged(permissions: IPermission[]) { |
|||
this.clientPermissionChanged = true |
|||
this.editClientPermissions = permissions |
|||
} |
|||
|
|||
/** 保存客户端权限 */ |
|||
private onSaveClientPemissions() { |
|||
if (this.clientPermissionChanged) { |
|||
const setClientPermissions = new UpdatePermissionsDto() |
|||
setClientPermissions.permissions = this.editClientPermissions |
|||
PermissionService.setPermissionsByKey('C', this.clientId, setClientPermissions).then(() => { |
|||
this.onFormClosed() |
|||
}) |
|||
} |
|||
} |
|||
|
|||
private onFormClosed() { |
|||
this.$emit('closed') |
|||
} |
|||
|
|||
/** 取消操作 */ |
|||
private onCancel() { |
|||
this.onFormClosed() |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.confirm { |
|||
position: absolute; |
|||
right: 10px; |
|||
} |
|||
.cancel { |
|||
position: absolute; |
|||
right: 120px; |
|||
} |
|||
</style> |
|||
@ -1,199 +0,0 @@ |
|||
<template> |
|||
<el-dialog |
|||
v-el-draggable-dialog |
|||
width="800px" |
|||
:visible="showDialog" |
|||
:title="$t('identityServer.clientProperty')" |
|||
custom-class="modal-form" |
|||
:show-close="false" |
|||
@close="onFormClosed" |
|||
> |
|||
<div class="app-container"> |
|||
<el-form |
|||
ref="formClientProperty" |
|||
label-width="100px" |
|||
:model="clientProperty" |
|||
:rules="clientPropertyRules" |
|||
> |
|||
<el-form-item |
|||
prop="key" |
|||
:label="$t('identityServer.propertyKey')" |
|||
> |
|||
<el-input |
|||
v-model="clientProperty.key" |
|||
:placeholder="$t('pleaseInputBy', {key: $t('identityServer.propertyKey')})" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="value" |
|||
:label="$t('identityServer.propertyValue')" |
|||
> |
|||
<el-input |
|||
v-model="clientProperty.value" |
|||
:placeholder="$t('pleaseInputBy', {key: $t('identityServer.propertyValue')})" |
|||
/> |
|||
</el-form-item> |
|||
|
|||
<el-form-item |
|||
style="text-align: center;" |
|||
label-width="0px" |
|||
> |
|||
<el-button |
|||
type="primary" |
|||
style="width:180px" |
|||
:disabled="!checkPermission(['IdentityServer.Clients.Properties.Create'])" |
|||
@click="onSaveClientProperty" |
|||
> |
|||
{{ $t('identityServer.createClientProperty') }} |
|||
</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
|
|||
<el-divider /> |
|||
|
|||
<el-table |
|||
row-key="key" |
|||
:data="clientProperties" |
|||
border |
|||
fit |
|||
highlight-current-row |
|||
style="width: 100%;" |
|||
> |
|||
<el-table-column |
|||
:label="$t('identityServer.propertyKey')" |
|||
prop="key" |
|||
sortable |
|||
width="200px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.key }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('identityServer.propertyValue')" |
|||
prop="value" |
|||
sortable |
|||
min-width="400px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.value }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('operaActions')" |
|||
align="center" |
|||
width="150px" |
|||
fixed="right" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<el-button |
|||
:disabled="!checkPermission(['IdentityServer.Clients.Properties.Delete'])" |
|||
size="mini" |
|||
type="primary" |
|||
@click="handleDeleteClientProperty(row.key, row.value)" |
|||
> |
|||
{{ $t('identityServer.deleteProperty') }} |
|||
</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import ClientService, { ClientProperty, ClientPropertyCreate } from '@/api/clients' |
|||
import { Component, Vue, Prop, Watch } from 'vue-property-decorator' |
|||
import { checkPermission } from '@/utils/permission' |
|||
|
|||
@Component({ |
|||
name: 'ClientPropertyEditForm', |
|||
methods: { |
|||
checkPermission |
|||
} |
|||
}) |
|||
export default class extends Vue { |
|||
@Prop({ default: false }) |
|||
private showDialog!: boolean |
|||
|
|||
@Prop({ default: '' }) |
|||
private clientId!: string |
|||
|
|||
@Prop({ default: () => new Array<ClientProperty>() }) |
|||
private clientProperties!: ClientProperty[] |
|||
|
|||
private clientProperty: ClientPropertyCreate |
|||
private clientPropertyRules = { |
|||
key: [ |
|||
{ required: true, message: this.l('pleaseInputBy', { key: this.l('identityServer.propertyKey') }), trigger: 'change' } |
|||
], |
|||
value: [ |
|||
{ required: true, message: this.l('pleaseInputBy', { key: this.l('identityServer.propertyValue') }), trigger: 'blur' } |
|||
] |
|||
} |
|||
|
|||
constructor() { |
|||
super() |
|||
this.clientProperty = new ClientPropertyCreate() |
|||
} |
|||
|
|||
@Watch('clientId', { immediate: true }) |
|||
private onClientIdChanged() { |
|||
this.clientProperty.clientId = this.clientId |
|||
} |
|||
|
|||
private handleDeleteClientProperty(key: string, value: string) { |
|||
this.$confirm(this.l('identityServer.deletePropertyByType', { key: key }), |
|||
this.l('identityServer.deleteProperty'), { |
|||
callback: (action) => { |
|||
if (action === 'confirm') { |
|||
ClientService.deleteClientProperty(this.clientId, key, value).then(() => { |
|||
const deletePropertyIndex = this.clientProperties.findIndex(p => p.key === key && p.value === value) |
|||
this.clientProperties.splice(deletePropertyIndex, 1) |
|||
this.$message.success(this.l('identityServer.deletePropertySuccess', { type: value })) |
|||
this.$emit('clientPropertyChanged') |
|||
}) |
|||
} |
|||
} |
|||
}) |
|||
} |
|||
|
|||
private onSaveClientProperty() { |
|||
const frmClientProperty = this.$refs.formClientProperty as any |
|||
frmClientProperty.validate((valid: boolean) => { |
|||
if (valid) { |
|||
this.clientProperty.clientId = this.clientId |
|||
ClientService.addClientProperty(this.clientProperty).then(property => { |
|||
this.clientProperties.push(property) |
|||
const successMessage = this.l('identityServer.createPropertySuccess', { type: this.clientProperty.key }) |
|||
this.$message.success(successMessage) |
|||
this.$emit('clientPropertyChanged') |
|||
this.onFormClosed() |
|||
}) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
private onFormClosed() { |
|||
this.resetFields() |
|||
this.$emit('closed') |
|||
} |
|||
|
|||
public resetFields() { |
|||
const frmClientProperty = this.$refs.formClientProperty as any |
|||
frmClientProperty.resetFields() |
|||
} |
|||
|
|||
private l(name: string, values?: any[] | { [key: string]: any }) { |
|||
return this.$t(name, values).toString() |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.full-select { |
|||
width: 100%; |
|||
} |
|||
</style> |
|||
@ -1,305 +0,0 @@ |
|||
<template> |
|||
<el-dialog |
|||
v-el-draggable-dialog |
|||
width="800px" |
|||
:visible="showDialog" |
|||
:title="$t('identityServer.clientSecret')" |
|||
custom-class="modal-form" |
|||
:show-close="false" |
|||
@close="onFormClosed" |
|||
> |
|||
<div class="app-container"> |
|||
<el-form |
|||
ref="formClientSecret" |
|||
label-width="100px" |
|||
:model="clientSecret" |
|||
:rules="clientSecretRules" |
|||
> |
|||
<el-form-item |
|||
prop="type" |
|||
:label="$t('identityServer.secretType')" |
|||
> |
|||
<el-select |
|||
v-model="clientSecret.type" |
|||
class="full-select" |
|||
:placeholder="$t('pleaseSelectBy', {key: $t('identityServer.secretType')})" |
|||
> |
|||
<el-option |
|||
key="JWK" |
|||
label="JsonWebKey" |
|||
value="JWK" |
|||
/> |
|||
<el-option |
|||
key="SharedSecret" |
|||
label="SharedSecret" |
|||
value="SharedSecret" |
|||
/> |
|||
<el-option |
|||
key="X509Name" |
|||
label="X509CertificateName" |
|||
value="X509Name" |
|||
/> |
|||
<el-option |
|||
key="X509CertificateBase64" |
|||
label="X509CertificateBase64" |
|||
value="X509CertificateBase64" |
|||
/> |
|||
<el-option |
|||
key="X509Thumbprint" |
|||
label="X509CertificateThumbprint" |
|||
value="X509Thumbprint" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="hashType" |
|||
:label="$t('identityServer.secretHashType')" |
|||
> |
|||
<el-popover |
|||
ref="popHashType" |
|||
placement="top-start" |
|||
trigger="hover" |
|||
:content="$t('identityServer.hashOnlySharedSecret')" |
|||
/> |
|||
<el-select |
|||
v-model="clientSecret.hashType" |
|||
v-popover:popHashType |
|||
:disabled="clientSecret.type !== 'SharedSecret'" |
|||
class="full-select" |
|||
:placeholder="$t('pleaseSelectBy', {key: $t('identityServer.secretHashType')})" |
|||
> |
|||
<el-option |
|||
:key="0" |
|||
label="Sha256" |
|||
:value="0" |
|||
/> |
|||
<el-option |
|||
:key="1" |
|||
label="Sha512" |
|||
:value="1" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="value" |
|||
:label="$t('identityServer.secretValue')" |
|||
> |
|||
<el-input |
|||
v-model="clientSecret.value" |
|||
:placeholder="$t('pleaseInputBy', {key: $t('identityServer.secretValue')})" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="description" |
|||
:label="$t('identityServer.secretDescription')" |
|||
> |
|||
<el-input |
|||
v-model="clientSecret.description" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="expiration" |
|||
:label="$t('identityServer.expiration')" |
|||
> |
|||
<el-date-picker |
|||
v-model="clientSecret.expiration" |
|||
class="full-select" |
|||
type="datetime" |
|||
/> |
|||
</el-form-item> |
|||
|
|||
<el-form-item |
|||
style="text-align: center;" |
|||
label-width="0px" |
|||
> |
|||
<el-button |
|||
type="primary" |
|||
style="width:180px" |
|||
:disabled="!checkPermission(['IdentityServer.Clients.Secrets.Create'])" |
|||
@click="onSaveClientSecret" |
|||
> |
|||
{{ $t('identityServer.createSecret') }} |
|||
</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
|
|||
<el-divider /> |
|||
|
|||
<el-table |
|||
row-key="clientId" |
|||
:data="clientSecrets" |
|||
border |
|||
fit |
|||
highlight-current-row |
|||
style="width: 100%;" |
|||
> |
|||
<el-table-column |
|||
:label="$t('identityServer.secretType')" |
|||
prop="type" |
|||
sortable |
|||
width="150px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.type }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('identityServer.secretValue')" |
|||
prop="value" |
|||
sortable |
|||
width="200px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.value }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('identityServer.secretDescription')" |
|||
prop="description" |
|||
width="170px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.description }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('identityServer.expiration')" |
|||
prop="expiration" |
|||
width="170px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.expiration | dateTimeFilter }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('operaActions')" |
|||
align="center" |
|||
width="150px" |
|||
fixed="right" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<el-button |
|||
:disabled="!checkPermission(['IdentityServer.Clients.Secrets.Delete'])" |
|||
size="mini" |
|||
type="primary" |
|||
@click="handleDeleteClientSecret(row.type, row.value)" |
|||
> |
|||
{{ $t('identityServer.deleteSecret') }} |
|||
</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import ClientService, { ClientSecret, ClientSecretCreate } from '@/api/clients' |
|||
import { Component, Vue, Prop, Watch } from 'vue-property-decorator' |
|||
import { dateFormat } from '@/utils/index' |
|||
import { checkPermission } from '@/utils/permission' |
|||
|
|||
@Component({ |
|||
name: 'ClientSecretEditForm', |
|||
filters: { |
|||
dateTimeFilter(datetime: string) { |
|||
if (datetime) { |
|||
const date = new Date(datetime) |
|||
return dateFormat(date, 'YYYY-mm-dd HH:MM') |
|||
} |
|||
return '' |
|||
} |
|||
}, |
|||
methods: { |
|||
checkPermission |
|||
} |
|||
}) |
|||
export default class extends Vue { |
|||
@Prop({ default: false }) |
|||
private showDialog!: boolean |
|||
|
|||
@Prop({ default: '' }) |
|||
private clientId!: string |
|||
|
|||
@Prop({ default: () => new Array<ClientSecret>() }) |
|||
private clientSecrets!: ClientSecret[] |
|||
|
|||
private clientSecretChanged: boolean |
|||
private clientSecret: ClientSecretCreate |
|||
private clientSecretRules = { |
|||
type: [ |
|||
{ required: true, message: this.l('pleaseSelectBy', { key: this.l('identityServer.secretType') }), trigger: 'change' } |
|||
], |
|||
value: [ |
|||
{ required: true, message: this.l('pleaseInputBy', { key: this.l('identityServer.secretValue') }), trigger: 'blur' } |
|||
] |
|||
} |
|||
|
|||
constructor() { |
|||
super() |
|||
this.clientSecretChanged = false |
|||
this.clientSecret = new ClientSecretCreate() |
|||
} |
|||
|
|||
@Watch('clientId', { immediate: true }) |
|||
private onClientIdChanged() { |
|||
this.clientSecret.clientId = this.clientId |
|||
} |
|||
|
|||
private handleDeleteClientSecret(type: string, value: string) { |
|||
this.$confirm(this.l('identityServer.deleteSecretByType', { type: value }), |
|||
this.l('identityServer.deleteSecret'), { |
|||
callback: (action) => { |
|||
if (action === 'confirm') { |
|||
ClientService.deleteClientSecret(this.clientId, type, value).then(() => { |
|||
const deleteSecretIndex = this.clientSecrets.findIndex(secret => secret.type === type) |
|||
this.clientSecrets.splice(deleteSecretIndex, 1) |
|||
this.$message.success(this.l('identityServer.deleteSecretSuccess', { type: value })) |
|||
this.$emit('clientSecretChanged') |
|||
}) |
|||
} |
|||
} |
|||
}) |
|||
} |
|||
|
|||
private onSaveClientSecret() { |
|||
const frmClientSecret = this.$refs.formClientSecret as any |
|||
frmClientSecret.validate((valid: boolean) => { |
|||
if (valid) { |
|||
this.clientSecret.clientId = this.clientId |
|||
ClientService.addClientSecret(this.clientSecret).then(secret => { |
|||
this.clientSecrets.push(secret) |
|||
const successMessage = this.l('identityServer.createSecretSuccess', { type: this.clientSecret.type }) |
|||
this.$message.success(successMessage) |
|||
this.$emit('clientSecretChanged') |
|||
this.onFormClosed() |
|||
}) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
private onFormClosed() { |
|||
this.resetFields() |
|||
this.$emit('closed') |
|||
} |
|||
|
|||
public resetFields() { |
|||
const frmClientSecret = this.$refs.formClientSecret as any |
|||
frmClientSecret.resetFields() |
|||
} |
|||
|
|||
private l(name: string, values?: any[] | { [key: string]: any }) { |
|||
return this.$t(name, values).toString() |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.full-select { |
|||
width: 100%; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,169 @@ |
|||
<template> |
|||
<div> |
|||
<el-form |
|||
v-if="allowedCreate" |
|||
ref="propertyEditForm" |
|||
label-width="100px" |
|||
:model="property" |
|||
> |
|||
<el-form-item |
|||
prop="key" |
|||
:label="$t('AbpIdentityServer.Propertites:Key')" |
|||
:rules="{ |
|||
required: true, |
|||
message: $t('pleaseInputBy', {key: $t('AbpIdentityServer.Propertites:Key')}), |
|||
trigger: 'blur' |
|||
}" |
|||
> |
|||
<el-input |
|||
v-model="property.key" |
|||
:placeholder="$t('pleaseInputBy', {key: $t('AbpIdentityServer.Propertites:Key')})" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="value" |
|||
:label="$t('AbpIdentityServer.Propertites:Value')" |
|||
:rules="{ |
|||
required: true, |
|||
message: $t('pleaseInputBy', {key: $t('AbpIdentityServer.Propertites:Value')}), |
|||
trigger: 'blur' |
|||
}" |
|||
> |
|||
<el-input |
|||
v-model="property.value" |
|||
:placeholder="$t('pleaseInputBy', {key: $t('AbpIdentityServer.Propertites:Value')})" |
|||
/> |
|||
</el-form-item> |
|||
|
|||
<el-form-item |
|||
style="text-align: center;" |
|||
label-width="0px" |
|||
> |
|||
<el-button |
|||
type="primary" |
|||
style="width:180px" |
|||
@click="onSave" |
|||
> |
|||
{{ $t('AbpIdentityServer.Propertites:New') }} |
|||
</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
|
|||
<el-table |
|||
row-key="key" |
|||
:data="editProperties" |
|||
border |
|||
fit |
|||
highlight-current-row |
|||
style="width: 100%;" |
|||
> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Propertites:Key')" |
|||
prop="key" |
|||
sortable |
|||
width="200px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.key }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Propertites:Value')" |
|||
prop="value" |
|||
sortable |
|||
min-width="300px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.value }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Actions')" |
|||
align="center" |
|||
width="80px" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<el-button |
|||
size="mini" |
|||
type="danger" |
|||
:disabled="!allowedDelete" |
|||
icon="el-icon-delete" |
|||
@click="onDelete(row.key)" |
|||
/> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { Component, Vue, Prop, Watch } from 'vue-property-decorator' |
|||
import { Form } from 'element-ui' |
|||
|
|||
class Property { |
|||
key = '' |
|||
value = '' |
|||
|
|||
constructor( |
|||
key: string, |
|||
value: string |
|||
) { |
|||
this.key = key |
|||
this.value = value |
|||
} |
|||
} |
|||
|
|||
@Component({ |
|||
name: 'PropertiesEditForm' |
|||
}) |
|||
export default class PropertiesEditForm extends Vue { |
|||
@Prop({ default: () => { return {} } }) |
|||
private properties!: {[key: string]: string} |
|||
|
|||
@Prop({ default: false }) |
|||
private allowedCreate!: boolean |
|||
|
|||
@Prop({ default: false }) |
|||
private allowedDelete!: boolean |
|||
|
|||
private editProperties = new Array<Property>() |
|||
private property = new Property('', '') |
|||
|
|||
@Watch('properties', { immediate: true, deep: true }) |
|||
private onPropertiesChanged() { |
|||
this.editProperties = new Array<Property>() |
|||
Object.keys(this.properties) |
|||
.forEach(key => { |
|||
this.editProperties.push(new Property(key, this.properties[key])) |
|||
}) |
|||
} |
|||
|
|||
private validateInput() { |
|||
return !this.editProperties.some(prop => prop.key === this.property.key) |
|||
} |
|||
|
|||
private onSave() { |
|||
const propertyEditForm = this.$refs.propertyEditForm as Form |
|||
propertyEditForm.validate(valid => { |
|||
if (valid) { |
|||
if (this.validateInput()) { |
|||
this.$emit('onCreated', this.property.key, this.property.value) |
|||
propertyEditForm.resetFields() |
|||
} else { |
|||
this.$message.warning(this.l('AbpIdentityServer.Propertites:DuplicateKey')) |
|||
} |
|||
} |
|||
}) |
|||
} |
|||
|
|||
private onDelete(key: string) { |
|||
this.$emit('onDeleted', key) |
|||
} |
|||
|
|||
private l(name: string, values?: any[] | { [key: string]: any }) { |
|||
return this.$t(name, values).toString() |
|||
} |
|||
} |
|||
</script> |
|||
@ -1,190 +0,0 @@ |
|||
<template> |
|||
<div style="width:auto; height:auto;"> |
|||
<div |
|||
class="el-input-tag input-tag-wrapper" |
|||
:class="[size ? 'el-input-tag--' + size : '']" |
|||
@click="foucusTagInput" |
|||
> |
|||
<span v-if="scopes.length>0"> |
|||
<el-tag |
|||
v-for="(scope, idx) in scopes" |
|||
:key="idx" |
|||
:size="size" |
|||
:closable="!readOnly" |
|||
:disable-transitions="false" |
|||
@close="remove(idx)" |
|||
> |
|||
{{ scope[key] }} |
|||
</el-tag> |
|||
</span> |
|||
<input |
|||
v-if="!readOnly" |
|||
v-model="newTag" |
|||
:size="size" |
|||
:class="[size ? 'tag-input--' + size : 'tag-input']" |
|||
@keydown="addNew" |
|||
@blur="addNew" |
|||
> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { Component, Vue, Prop } from 'vue-property-decorator' |
|||
import { AppModule } from '@/store/modules/app' |
|||
import { IScope } from '@/api/types' |
|||
|
|||
@Component({ |
|||
name: 'ScopeInput' |
|||
}) |
|||
export default class extends Vue { |
|||
@Prop({ default: () => new Array<IScope>() }) |
|||
private scopes!: IScope[] |
|||
|
|||
@Prop({ default: 'scope' }) |
|||
private key!: string |
|||
|
|||
@Prop({ default: () => [13, 188, 9] }) |
|||
private addTagOnKeys!: Array<number> |
|||
|
|||
@Prop({ default: false }) |
|||
private readOnly!: boolean |
|||
|
|||
private size = AppModule.size |
|||
public newTag: string |
|||
|
|||
constructor() { |
|||
super() |
|||
this.newTag = '' |
|||
} |
|||
|
|||
private foucusTagInput() { |
|||
const tagInputClass = this.size ? '.tag-input--' + this.size : '.tag-input' |
|||
if (this.readOnly || !this.$el.querySelector(tagInputClass)) { |
|||
|
|||
} else { |
|||
const tagInput = this.$el.querySelector(tagInputClass) as any |
|||
tagInput.focus() |
|||
} |
|||
} |
|||
|
|||
private addNew(e: any) { |
|||
if (e && (!this.addTagOnKeys.includes(e.keyCode)) && (e.type !== 'blur')) { |
|||
return false |
|||
} |
|||
if (e) { |
|||
e.stopPropagation() |
|||
e.preventDefault() |
|||
} |
|||
let addSuucess = false |
|||
if (this.newTag.includes(',')) { |
|||
this.newTag.split(',').forEach(item => { |
|||
if (this.addTag(item.trim())) { |
|||
addSuucess = true |
|||
} |
|||
}) |
|||
} else { |
|||
if (this.addTag(this.newTag.trim())) { |
|||
addSuucess = true |
|||
} |
|||
} |
|||
if (addSuucess) { |
|||
this.tagChange() |
|||
this.newTag = '' |
|||
} |
|||
} |
|||
|
|||
private addTag(tag: any) { |
|||
if (!tag) { |
|||
return false |
|||
} |
|||
tag = tag.trim() |
|||
if (!this.scopes.every(scope => scope.scope === tag)) { |
|||
this.scopes.push({ scope: tag }) |
|||
return true |
|||
} |
|||
return false |
|||
} |
|||
|
|||
private remove(index: number) { |
|||
this.scopes.splice(index, 1) |
|||
this.tagChange() |
|||
} |
|||
|
|||
private removeLastTa() { |
|||
if (this.newTag) { |
|||
return false |
|||
} |
|||
this.scopes.pop() |
|||
this.tagChange() |
|||
} |
|||
|
|||
private tagChange() { |
|||
this.$emit('input', this.scopes) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.input-tag-wrapper { |
|||
position: relative; |
|||
font-size: 14px; |
|||
background-color: #fff; |
|||
background-image: none; |
|||
border-radius: 4px; |
|||
border: 1px solid #dcdfe6; |
|||
box-sizing: border-box; |
|||
color: #606266; |
|||
display: inline-block; |
|||
outline: none; |
|||
padding: 0 5px 0 5px; |
|||
transition: border-color .2s cubic-bezier(.645,.045,.355,1); |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.el-tag { |
|||
margin-right: 4px; |
|||
margin-top: 4px; |
|||
} |
|||
|
|||
.tag-input--default { |
|||
background: transparent; |
|||
border: 0; |
|||
font-size: 14px; |
|||
height: 38px; |
|||
outline: none; |
|||
padding-left: 0; |
|||
width: 150px; |
|||
} |
|||
|
|||
.tag-input--mini{ |
|||
background: transparent; |
|||
border: 0; |
|||
font-size: 14px; |
|||
height: 26px; |
|||
outline: none; |
|||
padding-left: 0; |
|||
width: 150px; |
|||
} |
|||
|
|||
.tag-input--small{ |
|||
background: transparent; |
|||
border: 0; |
|||
font-size: 14px; |
|||
height: 30px; |
|||
outline: none; |
|||
padding-left: 0; |
|||
width: 150px; |
|||
} |
|||
|
|||
.tag-input--medium{ |
|||
background: transparent; |
|||
border: 0; |
|||
font-size: 14px; |
|||
height: 34px; |
|||
outline: none; |
|||
padding-left: 0; |
|||
width: 150px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,257 @@ |
|||
<template> |
|||
<div> |
|||
<el-form |
|||
v-if="allowedCreateSecret" |
|||
ref="secretEditForm" |
|||
:model="secret" |
|||
label-width="80px" |
|||
> |
|||
<el-form-item |
|||
prop="type" |
|||
:label="$t('AbpIdentityServer.Secret:Type')" |
|||
:rules="{ |
|||
required: true, |
|||
message: $t('pleaseSelectBy', {key: $t('AbpIdentityServer.Secret:Type')}), |
|||
trigger: 'blur' |
|||
}" |
|||
> |
|||
<el-select |
|||
v-model="secret.type" |
|||
class="full-select" |
|||
:placeholder="$t('pleaseSelectBy', {key: $t('AbpIdentityServer.Secret:Type')})" |
|||
> |
|||
<el-option |
|||
key="JWK" |
|||
label="JsonWebKey" |
|||
value="JWK" |
|||
/> |
|||
<el-option |
|||
key="SharedSecret" |
|||
label="SharedSecret" |
|||
value="SharedSecret" |
|||
/> |
|||
<el-option |
|||
key="X509Name" |
|||
label="X509CertificateName" |
|||
value="X509Name" |
|||
/> |
|||
<el-option |
|||
key="X509CertificateBase64" |
|||
label="X509CertificateBase64" |
|||
value="X509CertificateBase64" |
|||
/> |
|||
<el-option |
|||
key="X509Thumbprint" |
|||
label="X509CertificateThumbprint" |
|||
value="X509Thumbprint" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="hashType" |
|||
:label="$t('AbpIdentityServer.Secret:HashType')" |
|||
> |
|||
<el-popover |
|||
ref="popHashType" |
|||
placement="top-start" |
|||
trigger="hover" |
|||
:content="$t('AbpIdentityServer.Secret:HashTypeOnlySharedSecret')" |
|||
/> |
|||
<el-select |
|||
v-model="secret.hashType" |
|||
v-popover:popHashType |
|||
:disabled="secret.type !== 'SharedSecret'" |
|||
class="full-select" |
|||
:placeholder="$t('pleaseSelectBy', {key: $t('AbpIdentityServer.Secret:HashType')})" |
|||
> |
|||
<el-option |
|||
:key="0" |
|||
label="Sha256" |
|||
:value="0" |
|||
/> |
|||
<el-option |
|||
:key="1" |
|||
label="Sha512" |
|||
:value="1" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="value" |
|||
:label="$t('AbpIdentityServer.Secret:Value')" |
|||
:rules="{ |
|||
required: true, |
|||
message: $t('pleaseInputBy', {key: $t('AbpIdentityServer.Secret:Value')}), |
|||
trigger: 'blur' |
|||
}" |
|||
> |
|||
<el-input |
|||
v-model="secret.value" |
|||
:placeholder="$t('pleaseInputBy', {key: $t('AbpIdentityServer.Secret:Value')})" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="description" |
|||
:label="$t('AbpIdentityServer.Description')" |
|||
> |
|||
<el-input |
|||
v-model="secret.description" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item |
|||
prop="expiration" |
|||
:label="$t('AbpIdentityServer.Expiration')" |
|||
> |
|||
<el-date-picker |
|||
v-model="secret.expiration" |
|||
class="full-select" |
|||
type="datetime" |
|||
/> |
|||
</el-form-item> |
|||
|
|||
<el-form-item |
|||
style="text-align: center;" |
|||
label-width="0px" |
|||
> |
|||
<el-button |
|||
type="primary" |
|||
style="width:180px" |
|||
@click="onSave" |
|||
> |
|||
{{ $t('AbpIdentityServer.Secret:New') }} |
|||
</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
<el-table |
|||
row-key="value" |
|||
:data="secrets" |
|||
border |
|||
fit |
|||
highlight-current-row |
|||
style="width: 100%;" |
|||
> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Secret:Type')" |
|||
prop="type" |
|||
sortable |
|||
width="170px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.type }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Secret:Value')" |
|||
prop="value" |
|||
sortable |
|||
width="200px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.value }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Description')" |
|||
prop="description" |
|||
width="120px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.description }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Expiration')" |
|||
prop="expiration" |
|||
width="170px" |
|||
align="center" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<span>{{ row.expiration | dateTimeFilter }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
:label="$t('AbpIdentityServer.Actions')" |
|||
align="center" |
|||
width="80px" |
|||
fixed="right" |
|||
> |
|||
<template slot-scope="{row}"> |
|||
<el-button |
|||
:disabled="!allowedDeleteSecret" |
|||
type="danger" |
|||
icon="el-icon-delete" |
|||
size="mini" |
|||
@click="handleDeleteApiSecret(row.type, row.value)" |
|||
/> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { ISecret, HashType } from '@/api/types' |
|||
import { Component, Vue, Prop } from 'vue-property-decorator' |
|||
import { dateFormat } from '@/utils/index' |
|||
import { Form } from 'element-ui' |
|||
|
|||
class Secret implements ISecret { |
|||
type = '' |
|||
value = '' |
|||
hashType = HashType.Sha256 |
|||
description = '' |
|||
expiration: Date | undefined = undefined |
|||
} |
|||
|
|||
@Component({ |
|||
name: 'SecretEditForm', |
|||
filters: { |
|||
dateTimeFilter(datetime: string) { |
|||
if (datetime) { |
|||
const date = new Date(datetime) |
|||
return dateFormat(date, 'YYYY-mm-dd HH:MM:SS') |
|||
} |
|||
return '' |
|||
} |
|||
} |
|||
}) |
|||
export default class SecretEditForm extends Vue { |
|||
@Prop({ default: () => { return new Array<ISecret>() } }) |
|||
private secrets!: ISecret[] |
|||
|
|||
@Prop({ default: false }) |
|||
private allowedCreateSecret!: boolean |
|||
|
|||
@Prop({ default: false }) |
|||
private allowedDeleteSecret!: boolean |
|||
|
|||
private secret = new Secret() |
|||
|
|||
private onSave() { |
|||
const secretEditForm = this.$refs.secretEditForm as Form |
|||
secretEditForm.validate(valid => { |
|||
if (valid) { |
|||
this.$emit('onSecretCreated', this.secret) |
|||
secretEditForm.resetFields() |
|||
} |
|||
}) |
|||
} |
|||
|
|||
private handleDeleteApiSecret(type: string, value: string) { |
|||
this.$emit('onSecretDeleted', type, value) |
|||
} |
|||
|
|||
private l(name: string, values?: any[] | { [key: string]: any }) { |
|||
return this.$t(name, values).toString() |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.full-select { |
|||
width: 100%; |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue