Browse Source

add persisted grants manage view

pull/166/head
cKey 5 years ago
parent
commit
2793a44bea
  1. 20
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/en.json
  2. 20
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/zh-Hans.json
  3. 5
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application/LINGYUN/Abp/IdentityServer/AbpIdentityServerAutoMapperProfile.cs
  4. 2
      aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.EntityFrameworkCore/LINGYUN/Abp/IdentityServer/Grants/EfCorePersistentGrantRepository.cs
  5. BIN
      aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/event-bus-cap.db
  6. 31
      vueJs/src/api/dynamic-api.ts
  7. 20
      vueJs/src/api/grants.ts
  8. 2
      vueJs/src/views/admin/identityServer/api-scopes/components/ApiScopeCreateOrEditForm.vue
  9. 165
      vueJs/src/views/admin/identityServer/persisted-grants/components/PersistedGrantProfile.vue
  10. 230
      vueJs/src/views/admin/identityServer/persisted-grants/index.vue

20
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/en.json

@ -26,6 +26,12 @@
"ClientPropertyNotFound": "Client property: {0} not found!",
"IdentityResourcePropertyNotFound": "Identity resource property: {0} not found!",
"EncryptionNotImplemented": "Encryption type: {0} not implemented!",
"DisplayName:PersistedGrants": "Persisted Grants",
"DisplayName:Clients": "Clients",
"DisplayName:ApiResources": "Api Resources",
"DisplayName:ApiScopes": "Api Scopes",
"DisplayName:Devices": "Devices",
"DisplayName:IdentityResources": "Identity Resources",
"AddNew": "Add New",
"Basics": "Basics",
"Authentication": "Authentication",
@ -56,6 +62,7 @@
"Assigned": "Assigned",
"Available": "Available",
"Expiration": "Expiration",
"CreationTime": "Creation Time",
"Scope:New": "Add New",
"Scope:Delete": "Delete",
"Secret:New": "Add New",
@ -136,6 +143,17 @@
"Propertites:Value": "Value",
"Propertites:Delete": "Delete",
"Propertites:DuplicateKey": "Property already exists and cannot add duplicates!",
"Permissions": "Permissions"
"Permissions": "Permissions",
"ApiScopes:Edit": "Edit",
"ApiScopes:Delete": "Delete",
"Grants:Key": "Key",
"Grants:Type": "Type",
"Grants:SessionId": "Session Id",
"Grants:SubjectId": "Subject Id",
"Grants:ConsumedTime": "Consumed Time",
"Grants:Profile": "Profile",
"Grants:Delete": "Delete",
"Grants:DeleteByKey": "Delete By - {Key}",
"Grants:Data": "Data"
}
}

20
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/zh-Hans.json

@ -26,6 +26,12 @@
"ClientPropertyNotFound": "客户端属性: {0} 不存在!",
"IdentityResourcePropertyNotFound": "身份资源属性: {0} 不存在!",
"EncryptionNotImplemented": "加密类型: {0} 未实现!",
"DisplayName:PersistedGrants": "持久授权",
"DisplayName:Clients": "客户端",
"DisplayName:ApiResources": "Api资源",
"DisplayName:ApiScopes": "Api范围",
"DisplayName:Devices": "设备授权",
"DisplayName:IdentityResources": "身份资源",
"AddNew": "添加一个新的",
"Basics": "基本信息",
"Authentication": "认证/注销",
@ -55,7 +61,8 @@
"AllowedAccessTokenSigningAlgorithms": "允许访问令牌签名算法",
"Assigned": "可分配的",
"Available": "已拥有的",
"Expiration": "过期",
"Expiration": "过期时间",
"CreationTime": "创建时间",
"Scope:New": "添加新作用域",
"Scope:Delete": "删除作用域",
"Secret:New": "添加新密钥",
@ -138,6 +145,15 @@
"Propertites:DuplicateKey": "属性已经存在,不能添加重复项!",
"Permissions": "权限",
"ApiScopes:Edit": "编辑范围",
"ApiScopes:Delete": "删除范围"
"ApiScopes:Delete": "删除范围",
"Grants:Key": "授权标识",
"Grants:Type": "授权类型",
"Grants:SessionId": "会话标识",
"Grants:SubjectId": "主体标识",
"Grants:ConsumedTime": "消费时间",
"Grants:Profile": "明细",
"Grants:Delete": "删除",
"Grants:DeleteByKey": "删除授权标识 - {Key}",
"Grants:Data": "数据"
}
}

5
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application/LINGYUN/Abp/IdentityServer/AbpIdentityServerAutoMapperProfile.cs

@ -2,10 +2,12 @@
using LINGYUN.Abp.IdentityServer.ApiResources;
using LINGYUN.Abp.IdentityServer.ApiScopes;
using LINGYUN.Abp.IdentityServer.Clients;
using LINGYUN.Abp.IdentityServer.Grants;
using LINGYUN.Abp.IdentityServer.IdentityResources;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Grants;
using Volo.Abp.IdentityServer.IdentityResources;
namespace LINGYUN.Abp.IdentityServer
@ -47,6 +49,9 @@ namespace LINGYUN.Abp.IdentityServer
CreateMap<IdentityResourceProperty, IdentityResourcePropertyDto>();
CreateMap<IdentityResource, IdentityResourceDto>()
.MapExtraProperties();
CreateMap<PersistedGrant, PersistedGrantDto>()
.MapExtraProperties();
}
}
}

2
aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.EntityFrameworkCore/LINGYUN/Abp/IdentityServer/Grants/EfCorePersistentGrantRepository.cs

@ -41,7 +41,7 @@ namespace LINGYUN.Abp.IdentityServer.Grants
.WhereIf(!filter.IsNullOrWhiteSpace(), x =>
x.Type.Contains(filter) || x.ClientId.Contains(filter) || x.Key.Contains(filter))
.OrderBy(sorting ?? nameof(PersistedGrant.CreationTime))
.Page(skipCount, maxResultCount)
.PageBy(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellation));
}
}

BIN
aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/event-bus-cap.db

Binary file not shown.

31
vueJs/src/api/dynamic-api.ts

@ -8,6 +8,19 @@ import { Method } from 'axios'
const sourceUrl = '/api/abp/api-definition'
const serviceUrl = process.env.VUE_APP_BASE_API
export enum ParameterBindingSources {
modelBinding = 'ModelBinding',
query = 'Query',
body = 'Body',
path = 'Path',
form = 'Form',
header = 'Header',
custom = 'Custom',
services = 'Services'
}
const bindSources = [ParameterBindingSources.modelBinding, ParameterBindingSources.query]
export default class DynamicApiService {
/** api
* @param includeTypes
@ -44,14 +57,14 @@ export class UrlBuilder {
const value = HttpActionParameterHelper.findParameterValue(methodArguments, pathParameter)
if (!value) {
if (pathParameter.isOptional) {
urlBuilder = urlBuilder.replace(`{{${pathParameter.name}}}`, '')
urlBuilder = urlBuilder.replace(`{${pathParameter.name}}`, '')
} else if (pathParameter.defaultValue) {
urlBuilder = urlBuilder.replace(`{{${pathParameter.name}}}`, String(pathParameter.defaultValue))
urlBuilder = urlBuilder.replace(`{${pathParameter.name}}`, String(pathParameter.defaultValue))
} else {
throw new Error(`Missing path parameter value for ${pathParameter.name} (${pathParameter.nameOnMethod})`)
}
} else {
urlBuilder = urlBuilder.replace(`{{${pathParameter.name}}}`, String(value))
urlBuilder = urlBuilder.replace(`{${pathParameter.name}}`, String(value))
}
})
return urlBuilder
@ -63,7 +76,6 @@ export class UrlBuilder {
methodArguments: any,
apiVersion: ApiVersionInfo
) {
const bindSources = [ParameterBindingSources.modelBinding, ParameterBindingSources.query]
const queryStringParameters = actionParameters.filter(x => bindSources.some(b => b === x.bindingSourceId))
let isFirstParam = true
queryStringParameters
@ -142,17 +154,6 @@ export class ApiVersionInfo {
}
}
export enum ParameterBindingSources {
modelBinding = 'ModelBinding',
query = 'Query',
body = 'Body',
path = 'Path',
form = 'Form',
header = 'Header',
custom = 'Custom',
services = 'Services'
}
export class ControllerInterfaceApiDescriptionModel {
type!: string
}

20
vueJs/src/api/grants.ts

@ -0,0 +1,20 @@
import { ExtensibleEntity, PagedAndSortedResultRequestDto } from './types'
export class PersistedGrant extends ExtensibleEntity<string> {
key!: string
type!: string
subjectId?: string
sessionId!: string
description?: string
consumedTime?: Date
clientId!: string
creationTime!: Date
expiration?: Date
data!: string
}
export class GetGrantByPaged extends PagedAndSortedResultRequestDto {
filter = ''
subjectId = ''
}

2
vueJs/src/views/admin/identityServer/api-scopes/components/ApiScopeCreateOrEditForm.vue

@ -149,7 +149,7 @@ import UserClaimEditForm from '../../components/UserClaimEditForm.vue'
})
export default class extends Vue {
@Prop({ default: false })
private showDialog!: BooleanConstructor
private showDialog!: boolean
@Prop({ default: '' })
private id!: string

165
vueJs/src/views/admin/identityServer/persisted-grants/components/PersistedGrantProfile.vue

@ -0,0 +1,165 @@
<template>
<el-dialog
width="800px"
:title="$t('AbpIdentityServer.DisplayName:PersistedGrants')"
:visible="showDialog"
custom-class="modal-form"
@close="onFormClosed"
>
<div class="app-container">
<el-form
ref="formPersistedGrant"
label-width="130px"
>
<el-form-item
:label="$t('AbpIdentityServer.Grants:Key')"
>
<el-input
:value="persistedGrant.key"
readonly
/>
</el-form-item>
<el-form-item
:label="$t('AbpIdentityServer.Grants:Type')"
>
<el-input
:value="persistedGrant.type"
readonly
/>
</el-form-item>
<el-form-item
:label="$t('AbpIdentityServer.Grants:SubjectId')"
>
<el-input
:value="persistedGrant.subjectId"
readonly
/>
</el-form-item>
<el-form-item
:label="$t('AbpIdentityServer.Grants:SessionId')"
>
<el-input
:value="persistedGrant.sessionId"
readonly
/>
</el-form-item>
<el-form-item
:label="$t('AbpIdentityServer.Description')"
>
<el-input
:value="persistedGrant.description"
readonly
/>
</el-form-item>
<el-form-item
:label="$t('AbpIdentityServer.CreationTime')"
>
<el-input
:value="persistedGrant.creationTime | dateTimeFilter"
readonly
/>
</el-form-item>
<el-form-item
:label="$t('AbpIdentityServer.Grants:ConsumedTime')"
>
<el-input
:value="persistedGrant.consumedTime | dateTimeFilter"
readonly
/>
</el-form-item>
<el-form-item
:label="$t('AbpIdentityServer.Expiration')"
>
<el-input
:value="persistedGrant.expiration | dateTimeFilter"
readonly
/>
</el-form-item>
<el-form-item
:label="$t('AbpIdentityServer.Grants:Data')"
>
<json-editor
:value="formatData(persistedGrant.data)"
/>
</el-form-item>
</el-form>
</div>
</el-dialog>
</template>
<script lang="ts">
import { PersistedGrant } from '@/api/grants'
import { Component, Prop, Watch } from 'vue-property-decorator'
import { mixins } from 'vue-class-component'
import { dateFormat } from '@/utils/index'
import HttpProxyMiXin from '@/mixins/HttpProxyMiXin'
import JsonEditor from '@/components/JsonEditor/index.vue'
@Component({
name: 'PersistedGrantProfile',
components: {
JsonEditor
},
filters: {
dateTimeFilter(datetime: string) {
if (datetime) {
const date = new Date(datetime)
return dateFormat(date, 'YYYY-mm-dd HH:MM:SS')
}
return ''
}
}
})
export default class extends mixins(HttpProxyMiXin) {
@Prop({ default: false })
private showDialog!: boolean
@Prop({ default: '' })
private id!: string
private persistedGrant = new PersistedGrant()
get formatData() {
return (data: string) => {
if (data) {
return JSON.parse(data)
}
return {}
}
}
@Watch('showDialog', { immediate: true })
private onShowDialogChanged() {
this.handleGetPersistedGrant()
}
private handleGetPersistedGrant() {
if (this.id && this.showDialog) {
this.request<PersistedGrant>({
service: 'IdentityServer',
controller: 'PersistedGrant',
action: 'GetAsync',
data: {
id: this.id
}
}).then(res => {
this.persistedGrant = res
})
}
}
private onFormClosed() {
this.resetFields()
this.$emit('closed')
}
private onCancel() {
this.onFormClosed()
}
public resetFields() {
const formPersistedGrant = this.$refs.formPersistedGrant as any
formPersistedGrant.resetFields()
}
}
</script>

230
vueJs/src/views/admin/identityServer/persisted-grants/index.vue

@ -0,0 +1,230 @@
<template>
<div class="app-container">
<div class="filter-container">
<label
class="radio-label"
style="padding-left:10px;"
>{{ $t('queryFilter') }}</label>
<el-input
v-model="dataFilter.filter"
:placeholder="$t('filterString')"
style="width: 250px;margin-left: 10px;"
class="filter-item"
/>
<el-button
class="filter-item"
style="margin-left: 10px; text-alignt"
type="primary"
@click="refreshPagedData"
>
{{ $t('AbpIdentityServer.Search') }}
</el-button>
</div>
<el-table
v-loading="dataLoading"
row-key="id"
:data="dataList"
border
fit
highlight-current-row
style="width: 100%;"
@sort-change="handleSortChange"
>
<el-table-column
:label="$t('AbpIdentityServer.Client:Id')"
prop="clientId"
sortable
width="150px"
>
<template slot-scope="{row}">
<span>{{ row.clientId }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('AbpIdentityServer.Grants:Key')"
prop="key"
sortable
width="150px"
>
<template slot-scope="{row}">
<span>{{ row.key }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('AbpIdentityServer.Grants:Type')"
prop="type"
sortable
width="150px"
>
<template slot-scope="{row}">
<span>{{ row.type }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('AbpIdentityServer.Grants:SessionId')"
prop="sessionId"
sortable
width="140px"
>
<template slot-scope="{row}">
<span>{{ row.sessionId }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('AbpIdentityServer.Description')"
prop="description"
sortable
width="140px"
>
<template slot-scope="{row}">
<span>{{ row.description }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('global.operaActions')"
align="center"
width="250px"
>
<template slot-scope="{row}">
<el-button
size="mini"
type="success"
icon="el-icon-tickets"
@click="onShowProfile(row.id)"
>
{{ $t('AbpIdentityServer.Grants:Profile') }}
</el-button>
<el-button
:disabled="!checkPermission(['AbpIdentityServer.Grants.Delete'])"
size="mini"
type="danger"
icon="el-icon-delete"
@click="onDeleted(row.id, row.key)"
>
{{ $t('AbpIdentityServer.Grants:Delete') }}
</el-button>
</template>
</el-table-column>
</el-table>
<Pagination
v-show="dataTotal>0"
:total="dataTotal"
:page.sync="currentPage"
:limit.sync="pageSize"
@pagination="refreshPagedData"
@sort-change="handleSortChange"
/>
<PersistedGrantProfile
:id="selectId"
:show-dialog="showProfileDialog"
@closed="showProfileDialog=false"
/>
</div>
</template>
<script lang="ts">
import { dateFormat, abpPagerFormat } from '@/utils/index'
import { checkPermission } from '@/utils/permission'
import DataListMiXin from '@/mixins/DataListMiXin'
import HttpProxyMiXin from '@/mixins/HttpProxyMiXin'
import Component, { mixins } from 'vue-class-component'
import Pagination from '@/components/Pagination/index.vue'
import PersistedGrantProfile from './components/PersistedGrantProfile.vue'
import { GetGrantByPaged, PersistedGrant } from '@/api/grants'
@Component({
name: 'IdentityServerGrant',
components: {
Pagination,
PersistedGrantProfile
},
methods: {
checkPermission,
local(name: string) {
return this.$t(name)
}
},
filters: {
statusFilter(status: boolean) {
if (status) {
return 'success'
}
return 'warning'
},
datetimeFilter(val: string) {
const date = new Date(val)
return dateFormat(date, 'YYYY-mm-dd HH:MM')
}
}
})
export default class extends mixins(DataListMiXin, HttpProxyMiXin) {
public dataFilter = new GetGrantByPaged()
private selectId = ''
private showProfileDialog = false
mounted() {
this.refreshPagedData()
}
protected processDataFilter() {
this.dataFilter.skipCount = abpPagerFormat(this.currentPage, this.pageSize)
}
protected getPagedList(filter: any) {
return this.pagedRequest<PersistedGrant>({
service: 'IdentityServer',
controller: 'PersistedGrant',
action: 'GetListAsync',
data: {
input: filter
}
})
}
private onShowProfile(id: string) {
this.selectId = id
this.showProfileDialog = true
}
private onDeleted(id: string, key: string) {
this.$confirm(this.l('AbpIdentityServer.Grants:DeleteByKey', { Key: key }),
this.l('AbpUi.AreYouSure'), {
callback: (action) => {
if (action === 'confirm') {
this.request<void>({
service: 'IdentityServer',
controller: 'PersistedGrant',
action: 'DeleteAsync',
data: {
id: id
}
}).then(() => {
this.$message.success(this.l('global.successful'))
this.refreshPagedData()
})
}
}
})
}
}
</script>
<style lang="scss" scoped>
.roleItem {
width: 40px;
}
.options {
vertical-align: top;
margin-left: 20px;
}
.el-dropdown + .el-dropdown {
margin-left: 15px;
}
.el-icon-arrow-down {
font-size: 12px;
}
</style>
Loading…
Cancel
Save