Browse Source

️ 添加IdentityServer Domain层单元测试

🚑 修复单元测试检测出得Bug
pull/16/head 4.4.0.18
王军 4 years ago
parent
commit
5711a48b36
  1. 147
      aspnet-core/services/host/CompanyName.ProjectName.IdentityServer/Pages/Account/Login.cshtml
  2. 101
      aspnet-core/services/host/CompanyName.ProjectName.IdentityServer/Pages/Account/ReWriteLogin.cshtml
  3. 23
      aspnet-core/services/src/CompanyName.ProjectName.Domain/IdentityServer/IdenityServerApiResourceManager.cs
  4. 16
      aspnet-core/services/src/CompanyName.ProjectName.Domain/IdentityServer/IdenityServerApiScopeManager.cs
  5. 32
      aspnet-core/services/src/CompanyName.ProjectName.Domain/IdentityServer/IdenityServerClientManager.cs
  6. 27
      aspnet-core/services/src/CompanyName.ProjectName.Domain/IdentityServer/IdentityResourceManager.cs
  7. 89
      aspnet-core/services/test/CompanyName.ProjectName.Domain.Tests/IdentityServer/IdenityServerApiResourceManager_Tests.cs
  8. 86
      aspnet-core/services/test/CompanyName.ProjectName.Domain.Tests/IdentityServer/IdenityServerApiScopeManager_Tests.cs
  9. 202
      aspnet-core/services/test/CompanyName.ProjectName.Domain.Tests/IdentityServer/IdenityServerClientManager_Tests.cs
  10. 93
      aspnet-core/services/test/CompanyName.ProjectName.Domain.Tests/IdentityServer/IdentityResourceManager_Tests.cs
  11. 238
      aspnet-core/services/test/CompanyName.ProjectName.TestBase/IdentityServerDataSeedContributor.cs

147
aspnet-core/services/host/CompanyName.ProjectName.IdentityServer/Pages/Account/Login.cshtml

@ -1,101 +1,70 @@
@page
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.Account.Localization
@using Volo.Abp.Account.Settings
@using Volo.Abp.Settings
@model Volo.Abp.Account.Web.Pages.Account.LoginModel
@inject IHtmlLocalizer<AccountResource> L
@{
ViewData["Title"] = L["Login"];
Layout = null;
}
<head>
<title>@L["Login"]</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no" />
<link href="~/images/favicon.png" rel="icon" type="image/png">
<link href="~/fonts/open_sans_3_4_6_7.css" rel="stylesheet">
<link href="~/libs/nucleo/css/nucleo.css" rel="stylesheet" />
<link href="~/libs/@@fortawesome/fontawesome-free/css/all.css" rel="stylesheet" />
<link type="text/css" href="~/css/argon.min.css" rel="stylesheet">
<link type="text/css" href="~/css/site.css" rel="stylesheet">
<script src="~/libs/jquery/jquery.js"></script>
</head>
<div class="main-content">
<nav class="navbar navbar-top navbar-horizontal navbar-expand-md navbar-dark">
<div class="container px-4">
<a class="navbar-brand" href="/">
<img src="~/images/favicon.png" />
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar-collapse-main" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<div class="header bg-gradient-primary py-7 py-lg-8">
<div class="container">
<div class="header-body text-center mb-4">
<div class="row justify-content-center">
<div class="col-lg-5 col-md-6">
<h1 class="text-white">@L["Login"]</h1>
</div>
@inject Volo.Abp.Settings.ISettingProvider SettingProvider
<div class="card mt-3 shadow-sm rounded">
<div class="card-body p-5">
<h4>@L["Login"]</h4>
@* @if (await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled)) *@
@* { *@
@* <strong> *@
@* @L["AreYouANewUser"] *@
@* <a href="@Url.Page("./Register", new {returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash})" class="text-decoration-none">@L["Register"]</a> *@
@* </strong> *@
@* } *@
@if (Model.EnableLocalLogin)
{
<form method="post" class="mt-4">
<div class="form-group">
<label asp-for="LoginInput.UserNameOrEmailAddress"></label>
<input asp-for="LoginInput.UserNameOrEmailAddress" class="form-control"/>
<span asp-validation-for="LoginInput.UserNameOrEmailAddress" class="text-danger"></span>
</div>
</div>
</div>
<!-- 斜线 -->
<div class="separator separator-bottom separator-skew zindex-100">
<svg x="0" y="0" viewBox="0 0 2800 100" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
<polygon class="fill-default" points="2800 0 2800 100 0 100"></polygon>
</svg>
</div>
</div>
<div class="container mt--8 pb-5">
<div class="row justify-content-center">
<div class="col-lg-5 col-md-7">
<div class="card bg-secondary shadow border-0">
<div class="card-header bg-transparent pb-5">
</div>
<div class="card-body px-lg-5">
<form method="post">
<div class="form-group mb-3">
<div class="input-group input-group-alternative">
<div class="input-group-prepend">
<span class="input-group-text">
<i class="ni ni-email-83"></i>
</span>
</div>
<input asp-for="ReturnUrl" />
<input asp-for="ReturnUrlHash" />
<input asp-for="LoginInput.UserNameOrEmailAddress" class="form-control" />
<span asp-validation-for="LoginInput.UserNameOrEmailAddress" class="text-danger"></span>
</div>
<span class="invalid-feedback" style="display: block"></span>
</div>
<div class="form-group">
<div class="input-group input-group-alternative">
<div class="input-group-prepend">
<span class="input-group-text">
<i class="ni ni-lock-circle-open"></i>
</span>
</div>
<div class="form-group">
<label asp-for="LoginInput.Password"></label>
<input asp-for="LoginInput.Password" class="form-control"/>
<span asp-validation-for="LoginInput.Password" class="text-danger"></span>
</div>
<abp-row>
<abp-column>
<abp-input asp-for="LoginInput.RememberMe" class="mb-4"/>
</abp-column>
@* <abp-column class="text-right"> *@
@* <a href="@Url.Page("./ForgotPassword", new {returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash})">@L["ForgotPassword"]</a> *@
@* </abp-column> *@
</abp-row>
<abp-button type="submit" button-type="Primary" name="Action" value="Login" class="btn-block btn-lg mt-3">@L["Login"]</abp-button>
@if (Model.ShowCancelButton)
{
<abp-button type="submit" button-type="Secondary" formnovalidate="formnovalidate" name="Action" value="Cancel" class="btn-block btn-lg mt-3">@L["Cancel"]</abp-button>
}
</form>
}
<input asp-for="LoginInput.Password" class="form-control" />
<span asp-validation-for="LoginInput.Password" class="text-danger"></span>
</div>
@if (Model.VisibleExternalProviders.Any())
{
<div class="mt-2">
<h5>@L["OrLoginWith"]</h5>
<form asp-page="./Login" asp-page-handler="ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" asp-route-returnUrlHash="@Model.ReturnUrlHash" method="post">
@foreach (var provider in Model.VisibleExternalProviders)
{
<button type="submit" class="btn btn-primary m-1" name="provider" value="@provider.AuthenticationScheme" title="@L["LogInUsingYourProviderAccount", provider.DisplayName]">@provider.DisplayName</button>
}
</form>
</div>
}
</div>
<div class="text-center">
<button class="btn btn-primary my-4" type="submit" data-toggle="tooltip" data-placement="top" name="Action" value="Login">@L["Login"]</button>
</div>
</form>
</div>
</div>
@if (!Model.EnableLocalLogin && !Model.VisibleExternalProviders.Any())
{
<div class="alert alert-warning">
<strong>@L["InvalidLoginRequest"]</strong>
@L["ThereAreNoLoginSchemesConfiguredForThisClient"]
</div>
</div>
}
</div>
</div>

101
aspnet-core/services/host/CompanyName.ProjectName.IdentityServer/Pages/Account/ReWriteLogin.cshtml

@ -0,0 +1,101 @@
@page
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.Account.Localization
@model Volo.Abp.Account.Web.Pages.Account.LoginModel
@inject IHtmlLocalizer<AccountResource> L
@{
ViewData["Title"] = L["Login"];
Layout = null;
}
<head>
<title>@L["Login"]</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no" />
<link href="~/images/favicon.png" rel="icon" type="image/png">
<link href="~/fonts/open_sans_3_4_6_7.css" rel="stylesheet">
<link href="~/libs/nucleo/css/nucleo.css" rel="stylesheet" />
<link href="~/libs/@@fortawesome/fontawesome-free/css/all.css" rel="stylesheet" />
<link type="text/css" href="~/css/argon.min.css" rel="stylesheet">
<link type="text/css" href="~/css/site.css" rel="stylesheet">
<script src="~/libs/jquery/jquery.js"></script>
</head>
<div class="main-content">
<nav class="navbar navbar-top navbar-horizontal navbar-expand-md navbar-dark">
<div class="container px-4">
<a class="navbar-brand" href="/">
<img src="~/images/favicon.png" />
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar-collapse-main" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<div class="header bg-gradient-primary py-7 py-lg-8">
<div class="container">
<div class="header-body text-center mb-4">
<div class="row justify-content-center">
<div class="col-lg-5 col-md-6">
<h1 class="text-white">@L["Login"]</h1>
</div>
</div>
</div>
</div>
<!-- 斜线 -->
<div class="separator separator-bottom separator-skew zindex-100">
<svg x="0" y="0" viewBox="0 0 2800 100" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
<polygon class="fill-default" points="2800 0 2800 100 0 100"></polygon>
</svg>
</div>
</div>
<div class="container mt--8 pb-5">
<div class="row justify-content-center">
<div class="col-lg-5 col-md-7">
<div class="card bg-secondary shadow border-0">
<div class="card-header bg-transparent pb-5">
</div>
<div class="card-body px-lg-5">
<form method="post">
<div class="form-group mb-3">
<div class="input-group input-group-alternative">
<div class="input-group-prepend">
<span class="input-group-text">
<i class="ni ni-email-83"></i>
</span>
</div>
<input asp-for="ReturnUrl" />
<input asp-for="ReturnUrlHash" />
<input asp-for="LoginInput.UserNameOrEmailAddress" class="form-control" />
<span asp-validation-for="LoginInput.UserNameOrEmailAddress" class="text-danger"></span>
</div>
<span class="invalid-feedback" style="display: block"></span>
</div>
<div class="form-group">
<div class="input-group input-group-alternative">
<div class="input-group-prepend">
<span class="input-group-text">
<i class="ni ni-lock-circle-open"></i>
</span>
</div>
<input asp-for="LoginInput.Password" class="form-control" />
<span asp-validation-for="LoginInput.Password" class="text-danger"></span>
</div>
</div>
<div class="text-center">
<button class="btn btn-primary my-4" type="submit" data-toggle="tooltip" data-placement="top" name="Action" value="Login">@L["Login"]</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>

23
aspnet-core/services/src/CompanyName.ProjectName.Domain/IdentityServer/IdenityServerApiResourceManager.cs

@ -20,18 +20,20 @@ namespace CompanyName.ProjectName.IdentityServer
}
public Task<List<ApiResource>> GetListAsync(
int skipCount,
int maxResultCount,
int skipCount = 0,
int maxResultCount = 10,
string filter = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return _apiResourceRepository.GetListAsync("CreationTime desc", skipCount, maxResultCount, filter,
return _apiResourceRepository.GetListAsync("CreationTime desc", skipCount,
maxResultCount, filter,
includeDetails,
cancellationToken);
}
public Task<long> GetCountAsync(string filter = null, CancellationToken cancellationToken = default)
public Task<long> GetCountAsync(string filter = null,
CancellationToken cancellationToken = default)
{
return _apiResourceRepository.GetCountAsync(filter,
cancellationToken);
@ -81,7 +83,8 @@ namespace CompanyName.ProjectName.IdentityServer
//
// properties?.Distinct().ToList().ForEach(item => { apiResource.AddProperty(item.Key, item.Value); });
return await _apiResourceRepository.InsertAsync(apiResource, cancellationToken: cancellationToken);
return await _apiResourceRepository.InsertAsync(apiResource,
cancellationToken: cancellationToken);
}
public async Task DeleteAsync(
@ -136,13 +139,17 @@ namespace CompanyName.ProjectName.IdentityServer
apiResource.Scopes.Clear();
foreach (var item in scopes)
if (scopes != null)
{
apiResource.AddScope(item);
foreach (var item in scopes)
{
apiResource.AddScope(item);
}
}
return await _apiResourceRepository.UpdateAsync(apiResource, cancellationToken: cancellationToken);
return await _apiResourceRepository.UpdateAsync(apiResource,
cancellationToken: cancellationToken);
}
}
}

16
aspnet-core/services/src/CompanyName.ProjectName.Domain/IdentityServer/IdenityServerApiScopeManager.cs

@ -18,8 +18,8 @@ namespace CompanyName.ProjectName.IdentityServer
}
public Task<List<ApiScope>> GetListAsync(
int skipCount,
int maxResultCount,
int skipCount = 0,
int maxResultCount = 10,
string filter = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
@ -33,7 +33,8 @@ namespace CompanyName.ProjectName.IdentityServer
cancellationToken);
}
public Task<long> GetCountAsync(string filter = null, CancellationToken cancellationToken = default)
public Task<long> GetCountAsync(string filter = null,
CancellationToken cancellationToken = default)
{
return _apiScopeRepository.GetCountAsync(filter, cancellationToken);
}
@ -50,7 +51,8 @@ namespace CompanyName.ProjectName.IdentityServer
var apiScope = await _apiScopeRepository.GetByNameAsync(name, false);
if (null != apiScope) throw new UserFriendlyException(message: $"{name}已存在");
apiScope = new ApiScope(GuidGenerator.Create(), name, displayName, description, required, emphasize,
apiScope = new ApiScope(GuidGenerator.Create(), name, displayName, description,
required, emphasize,
showInDiscoveryDocument, enabled);
return await _apiScopeRepository.InsertAsync(apiScope);
}
@ -81,9 +83,11 @@ namespace CompanyName.ProjectName.IdentityServer
return _apiScopeRepository.DeleteAsync(id, autoSave, cancellationToken);
}
public async Task<List<ApiScope>> FindAllAsync(CancellationToken cancellationToken = default)
public async Task<List<ApiScope>> FindAllAsync(
CancellationToken cancellationToken = default)
{
return await _apiScopeRepository.GetListAsync(e => e.Enabled == true, false, cancellationToken);
return await _apiScopeRepository.GetListAsync(e => e.Enabled == true, false,
cancellationToken);
}
}
}

32
aspnet-core/services/src/CompanyName.ProjectName.Domain/IdentityServer/IdenityServerClientManager.cs

@ -22,36 +22,40 @@ namespace CompanyName.ProjectName.IdentityServer
public Task<List<Client>> GetListAsync(
int skipCount,
int maxResultCount,
int skipCount = 0,
int maxResultCount = 10,
string filter = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return _clientRepository.GetListAsync("CreationTime desc", skipCount, maxResultCount, filter, includeDetails,
return _clientRepository.GetListAsync("CreationTime desc", skipCount, maxResultCount,
filter, includeDetails,
cancellationToken);
}
public Task<long> GetCountAsync(string filter = null, CancellationToken cancellationToken = default)
public Task<long> GetCountAsync(string filter = null,
CancellationToken cancellationToken = default)
{
return _clientRepository.GetCountAsync(filter,
cancellationToken);
}
public Task DeleteAsync(Guid id, bool autoSave = false, CancellationToken cancellationToken = default)
public Task DeleteAsync(Guid id, bool autoSave = false,
CancellationToken cancellationToken = default)
{
return _clientRepository.DeleteAsync(id, autoSave, default);
}
public async Task<Client> CreateAsync(string clientId, string clientName, string description, string allowedGrantTypes)
public async Task<Client> CreateAsync(string clientId, string clientName,
string description, string allowedGrantTypes)
{
var entity = await _clientRepository.FindByClientIdAsync(clientId);
if (null != entity) throw new UserFriendlyException(message: "当前ClientId已存在");
entity = new Client(GuidGenerator.Create(), clientId)
{
ClientName = clientName, Description = description
ClientName = clientName, Description = description,
ClientClaimsPrefix = "client_"
};
entity.ClientClaimsPrefix="client_";
entity.AddGrantType(allowedGrantTypes);
return await _clientRepository.InsertAsync(entity);
}
@ -160,7 +164,6 @@ namespace CompanyName.ProjectName.IdentityServer
client.ClientSecrets.Clear();
client.AddSecret(secret.ToSha256(), null, secretType, String.Empty);
}
}
}
@ -179,8 +182,15 @@ namespace CompanyName.ProjectName.IdentityServer
var client = await _clientRepository.FindByClientIdAsync(clientId);
if (client == null) throw new UserFriendlyException(message: $"{clientId}不存在");
client.RemoveAllScopes();
scopes.ForEach(item => { client.AddScope(item.Trim()); });
foreach (var item in scopes.Distinct())
{
if (item.IsNotNullOrWhiteSpace())
{
client.AddScope(item.Trim());
}
}
return await _clientRepository.UpdateAsync(client);
}

27
aspnet-core/services/src/CompanyName.ProjectName.Domain/IdentityServer/IdentityResourceManager.cs

@ -18,9 +18,9 @@ namespace CompanyName.ProjectName.IdentityServer
}
public Task<List<IdentityResource>> GetListAsync(
int skipCount,
int maxResultCount,
string filter,
int skipCount = 0,
int maxResultCount = 10,
string filter = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
@ -33,22 +33,16 @@ namespace CompanyName.ProjectName.IdentityServer
cancellationToken);
}
public Task<List<IdentityResource>> GetAllAsync(CancellationToken cancellationToken = default)
public Task<List<IdentityResource>> GetAllAsync(
CancellationToken cancellationToken = default)
{
return _identityResourceRepository.GetListAsync(true, cancellationToken);
}
public Task<long> GetCountAsync(string filter = null, CancellationToken cancellationToken = default)
{
return _identityResourceRepository.GetCountAsync(filter, cancellationToken);
}
public Task<IdentityResource> FindByNameAsync(
string name,
bool includeDetails = true,
public Task<long> GetCountAsync(string filter = null,
CancellationToken cancellationToken = default)
{
return _identityResourceRepository.FindByNameAsync(name, includeDetails, cancellationToken);
return _identityResourceRepository.GetCountAsync(filter, cancellationToken);
}
@ -63,9 +57,10 @@ namespace CompanyName.ProjectName.IdentityServer
{
var identityResource = await _identityResourceRepository.FindByNameAsync(name, false);
if (null != identityResource) throw new UserFriendlyException(message: $"{name}已存在");
identityResource = new IdentityResource(GuidGenerator.Create(), name, displayName, description, required,
emphasize,
showInDiscoveryDocument, enabled);
identityResource = new IdentityResource(GuidGenerator.Create(), name, displayName,
description, enabled,
required,
false, showInDiscoveryDocument);
return await _identityResourceRepository.InsertAsync(identityResource);
}

89
aspnet-core/services/test/CompanyName.ProjectName.Domain.Tests/IdentityServer/IdenityServerApiResourceManager_Tests.cs

@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using Shouldly;
using Volo.Abp;
using Xunit;
namespace CompanyName.ProjectName.IdentityServer
{
public class IdenityServerApiResourceManager_Tests : ProjectNameDomainTestBase
{
private readonly IdenityServerApiResourceManager _idenityServerApiResourceManager;
public IdenityServerApiResourceManager_Tests()
{
_idenityServerApiResourceManager =
GetRequiredService<IdenityServerApiResourceManager>();
}
[Fact]
public async Task Shuold_GetListAsync_Ok()
{
var result = await _idenityServerApiResourceManager.GetListAsync();
result.Count.ShouldBe(1);
result.FirstOrDefault()?.Name.ShouldBe("ApiResource_Test");
}
[Fact]
public async Task Shuold_GetListAsync_Filter_Ok()
{
var result =
await _idenityServerApiResourceManager.GetListAsync(filter: "ApiResource_Test");
result.Count.ShouldBe(1);
result.FirstOrDefault()?.Name.ShouldBe("ApiResource_Test");
}
[Fact]
public async Task Shuold_GetCountAsync_Ok()
{
var result = await _idenityServerApiResourceManager.GetCountAsync();
result.ShouldBe(1);
}
[Fact]
public async Task Shuold_GetCountAsync_Filter_Ok()
{
var result = await _idenityServerApiResourceManager.GetCountAsync(filter:"ApiResource_Test");
result.ShouldBe(1);
}
[Fact]
public async Task Shuold_CreateAsync_Ok()
{
var result = await _idenityServerApiResourceManager.CreateAsync(Guid.NewGuid(),
"Create_ApiResource", "单元测试创建", "Xunit", true, "", false, "1q2w3E*");
result.Name.ShouldBe("Create_ApiResource");
}
[Fact]
public async Task Shuold_CreateAsync_Name_Repetition_Exception()
{
(await Should.ThrowAsync<UserFriendlyException>(async () =>
{
var result = await _idenityServerApiResourceManager.CreateAsync(Guid.NewGuid(),
"ApiResource_Test", "单元测试创建", "Xunit", true, "", false, "1q2w3E*");
})).Message.ShouldBe("ApiResource已存在");
}
[Fact]
public async Task Shuold_UpdateAsync_Ok()
{
var result = await _idenityServerApiResourceManager.UpdateAsync("ApiResource_Test",
"Update", "Update_Desc", false, "", true,
"123456", new List<string>());
result.Name.ShouldBe("ApiResource_Test");
result.DisplayName.ShouldBe("Update");
result.Enabled.ShouldBeFalse();
}
[Fact]
public async Task Shuold_DeleteAsync_Ok()
{
await _idenityServerApiResourceManager.DeleteAsync(Guid.NewGuid());
}
}
}

86
aspnet-core/services/test/CompanyName.ProjectName.Domain.Tests/IdentityServer/IdenityServerApiScopeManager_Tests.cs

@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp;
using Xunit;
namespace CompanyName.ProjectName.IdentityServer
{
public class IdenityServerApiScopeManager_Tests : ProjectNameDomainTestBase
{
private readonly IdenityServerApiScopeManager _idenityServerApiScopeManager;
public IdenityServerApiScopeManager_Tests()
{
_idenityServerApiScopeManager = GetRequiredService<IdenityServerApiScopeManager>();
}
[Fact]
public async Task Shuold_GetListAsync_Ok()
{
var result = await _idenityServerApiScopeManager.GetListAsync();
result.Count.ShouldBe(1);
result.FirstOrDefault()?.Name.ShouldBe("ApiScope_Test");
}
[Fact]
public async Task Shuold_GetListAsync_Filter_Ok()
{
var result =
await _idenityServerApiScopeManager.GetListAsync(filter: "ApiScope_Test");
result.Count.ShouldBe(1);
result.FirstOrDefault()?.Name.ShouldBe("ApiScope_Test");
}
[Fact]
public async Task Shuold_GetCountAsync_Ok()
{
var result = await _idenityServerApiScopeManager.GetCountAsync();
result.ShouldBe(1);
}
[Fact]
public async Task Shuold_GetCountAsync_Filter_Ok()
{
var result = await _idenityServerApiScopeManager.GetCountAsync(filter: "ApiScope_Test");
result.ShouldBe(1);
}
[Fact]
public async Task Shuold_CreateAsync_Ok()
{
var result = await _idenityServerApiScopeManager.CreateAsync(
"Create_ApiScope", "单元测试创建", "Xunit", true, false, false, true);
result.Name.ShouldBe("Create_ApiScope");
}
[Fact]
public async Task Shuold_CreateAsync_Name_Repetition_Exception()
{
(await Should.ThrowAsync<UserFriendlyException>(async () =>
{
var result = await _idenityServerApiScopeManager.CreateAsync(
"ApiScope_Test", "单元测试创建", "Xunit", true, false, false, true);
})).Message.ShouldBe("ApiScope_Test已存在");
}
[Fact]
public async Task Shuold_UpdateAsync_Ok()
{
var result = await _idenityServerApiScopeManager.UpdateAsync("ApiScope_Test",
"Update", "Update_Desc", true, true, true,
true);
result.DisplayName.ShouldBe("Update");
result.Enabled.ShouldBeTrue();
}
[Fact]
public async Task Shuold_DeleteAsync_Ok()
{
await _idenityServerApiScopeManager.DeleteAsync(Guid.NewGuid());
}
}
}

202
aspnet-core/services/test/CompanyName.ProjectName.Domain.Tests/IdentityServer/IdenityServerClientManager_Tests.cs

@ -0,0 +1,202 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp;
using Xunit;
namespace CompanyName.ProjectName.IdentityServer
{
public class IdenityServerClientManager_Tests : ProjectNameDomainTestBase
{
private readonly IdenityServerClientManager _idenityServerClientManager;
public IdenityServerClientManager_Tests()
{
_idenityServerClientManager = GetRequiredService<IdenityServerClientManager>();
}
[Fact]
public async Task Shuold_GetListAsync_Ok()
{
var result = await _idenityServerClientManager.GetListAsync();
result.ShouldNotBeNull();
result.FirstOrDefault()?.ClientName.ShouldBe("Test_Client");
}
[Fact]
public async Task Shuold_GetListAsync_Filter_Ok()
{
var result =
await _idenityServerClientManager.GetListAsync(filter: "Test_Client");
result.ShouldNotBeNull();
result.FirstOrDefault()?.ClientName.ShouldBe("Test_Client");
}
[Fact]
public async Task Shuold_GetCountAsync_Ok()
{
var result = await _idenityServerClientManager.GetCountAsync();
result.ShouldBeGreaterThan(0);
}
[Fact]
public async Task Shuold_GetCountAsync_Filter_Ok()
{
var result = await _idenityServerClientManager.GetCountAsync(filter: "Test_Client");
result.ShouldBeGreaterThan(0);
}
[Fact]
public async Task Shuold_CreateAsync_Ok()
{
var result =
await _idenityServerClientManager.CreateAsync("Xunit", "XunitName", "desc", "test");
result.ClientName.ShouldBe("XunitName");
result.Enabled.ShouldBeTrue();
}
[Fact]
public async Task Shuold_CreateAsync_Name_Repetition_Exception()
{
(await Should.ThrowAsync<UserFriendlyException>(async () =>
{
var result =
await _idenityServerClientManager.CreateAsync("Test_Client", "XunitName",
"desc", "test");
})).Message.ShouldBe("当前ClientId已存在");
}
[Fact]
public async Task Shuold_UpdateBasicDataAsync_Ok()
{
var result = await _idenityServerClientManager.UpdateBasicDataAsync(
"Test_Client",
"单元测试",
"desc",
"clientUrl",
"logoUrl",
false,
"http",
false,
false,
false,
false,
false,
false,
false,
false,
"logoutUrl",
false,
"backLogoutUrl",
false,
false,
300,
"unit",
3500,
3400,
3300,
3200,
3100,
false,
3000,
1,
false,
false,
false,
"client",
"salt",
2900,
"user",
2600,
2800,
"123456",
"123456",
"sc"
);
result.Description.ShouldBe("desc");
result.Enabled.ShouldBeFalse();
result.AccessTokenLifetime.ShouldBe(3500);
result.AuthorizationCodeLifetime.ShouldBe(3400);
result.IdentityTokenLifetime.ShouldBe(300);
result.RefreshTokenExpiration.ShouldBe(3000);
}
[Fact]
public async Task Shuold_UpdateScopesAsync_Ok()
{
var result =
await _idenityServerClientManager.UpdateScopesAsync("Test_Client",
new List<string>() { "001","002" });
result.AllowedScopes.Count.ShouldBe(2);
}
[Fact]
public async Task Shuold_AddRedirectUriAsync_Ok()
{
var result =
await _idenityServerClientManager.AddRedirectUriAsync("Test_Client","doc.cncore.club");
result.RedirectUris.FirstOrDefault(e => e.RedirectUri == "doc.cncore.club")
.ShouldNotBeNull();
}
[Fact]
public async Task Shuold_RemoveRedirectUriAsync_Ok()
{
await WithUnitOfWorkAsync(async () => { await _idenityServerClientManager.AddRedirectUriAsync("Test_Client","doc.cncore.club");; });
var result =
await _idenityServerClientManager.RemoveRedirectUriAsync("Test_Client","doc.cncore.club");
result.RedirectUris.FirstOrDefault(e => e.RedirectUri == "doc.cncore.club")
.ShouldBeNull();
}
[Fact]
public async Task Shuold_AddLogoutRedirectUriAsync_Ok()
{
var result =
await _idenityServerClientManager.AddLogoutRedirectUriAsync("Test_Client","doc.cncore.club");
result.PostLogoutRedirectUris.Any(e=>e.PostLogoutRedirectUri=="doc.cncore.club").ShouldBeTrue();
}
[Fact]
public async Task Shuold_RemoveLogoutRedirectUriAsync_Ok()
{
await WithUnitOfWorkAsync(async () => { await _idenityServerClientManager.AddLogoutRedirectUriAsync("Test_Client","doc.cncore.club");; });
var result =
await _idenityServerClientManager.RemoveLogoutRedirectUriAsync("Test_Client","doc.cncore.club");
result.PostLogoutRedirectUris.Any(e=>e.PostLogoutRedirectUri=="doc.cncore.club").ShouldBeFalse();
}
[Fact]
public async Task Shuold_AddCorsAsync_Ok()
{
var result =
await _idenityServerClientManager.AddCorsAsync("Test_Client","doc.cncore.club");
result.AllowedCorsOrigins.FirstOrDefault(e => e.Origin == "doc.cncore.club")
.ShouldNotBeNull();
}
[Fact]
public async Task Shuold_RemoveCorsAsync_Ok()
{
await WithUnitOfWorkAsync(async () => { await _idenityServerClientManager.AddCorsAsync("Test_Client","doc.cncore.club");; });
var result =
await _idenityServerClientManager.RemoveCorsAsync("Test_Client","doc.cncore.club");
result.AllowedCorsOrigins.FirstOrDefault(e => e.Origin == "doc.cncore.club")
.ShouldBeNull();
}
[Fact]
public async Task Shuold_EnabledAsync_Ok()
{
var result =
await _idenityServerClientManager.EnabledAsync("Test_Client",false);
result.Enabled.ShouldBeFalse();
}
}
}

93
aspnet-core/services/test/CompanyName.ProjectName.Domain.Tests/IdentityServer/IdentityResourceManager_Tests.cs

@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp;
using Xunit;
namespace CompanyName.ProjectName.IdentityServer
{
public class IdentityResourceManager_Tests : ProjectNameDomainTestBase
{
private readonly IdentityResourceManager _identityResourceManager;
public IdentityResourceManager_Tests()
{
_identityResourceManager = GetRequiredService<IdentityResourceManager>();
}
[Fact]
public async Task Shuold_GetListAsync_Ok()
{
var result = await _identityResourceManager.GetListAsync();
result.ShouldNotBeNull();
}
[Fact]
public async Task Shuold_GetListAsync_Filter_Ok()
{
var result =
await _identityResourceManager.GetListAsync(filter: "openid");
result.FirstOrDefault()?.Name.ShouldBe("openid");
}
[Fact]
public async Task Shuold_GetCountAsync_Ok()
{
var result = await _identityResourceManager.GetCountAsync();
result.ShouldBeGreaterThan(0);
}
[Fact]
public async Task Shuold_GetCountAsync_Filter_Ok()
{
var result = await _identityResourceManager.GetCountAsync(filter: "openid");
result.ShouldBeGreaterThan(0);
}
[Fact]
public async Task Shuold_CreateAsync_Ok()
{
var result = await _identityResourceManager.CreateAsync("Create_Identity", "单元测试",
"desc", true, false,
false,
false);
result.Name.ShouldBe("Create_Identity");
result.Enabled.ShouldBeTrue();
result.ShowInDiscoveryDocument.ShouldBeFalse();
}
[Fact]
public async Task Shuold_CreateAsync_Name_Repetition_Exception()
{
(await Should.ThrowAsync<UserFriendlyException>(async () =>
{
var result = await _identityResourceManager.CreateAsync("openid", "单元测试",
"desc", true, false,
false,
false);
})).Message.ShouldBe("openid已存在");
}
[Fact]
public async Task Shuold_UpdateAsync_Ok()
{
var result = await _identityResourceManager.UpdateAsync("openid", "单元测试",
"desc", false, false,
false,
false);
result.DisplayName.ShouldBe("单元测试");
result.Enabled.ShouldBeFalse();
}
[Fact]
public async Task Shuold_DeleteAsync_Ok()
{
await _identityResourceManager.DeleteAsync(Guid.NewGuid());
}
}
}

238
aspnet-core/services/test/CompanyName.ProjectName.TestBase/IdentityServerDataSeedContributor.cs

@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using IdentityServer4.Models;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.IdentityResources;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement;
using Volo.Abp.Uow;
using ApiResource = Volo.Abp.IdentityServer.ApiResources.ApiResource;
using ApiScope = Volo.Abp.IdentityServer.ApiScopes.ApiScope;
using Client = Volo.Abp.IdentityServer.Clients.Client;
namespace CompanyName.ProjectName
{
public class IdentityServerDataSeedContributor : IDataSeedContributor, ITransientDependency
{
private readonly IApiResourceRepository _apiResourceRepository;
private readonly IApiScopeRepository _apiScopeRepository;
private readonly IClientRepository _clientRepository;
private readonly IIdentityResourceDataSeeder _identityResourceDataSeeder;
private readonly IGuidGenerator _guidGenerator;
private readonly IPermissionDataSeeder _permissionDataSeeder;
private readonly ICurrentTenant _currentTenant;
public IdentityServerDataSeedContributor(
IClientRepository clientRepository,
IApiResourceRepository apiResourceRepository,
IApiScopeRepository apiScopeRepository,
IIdentityResourceDataSeeder identityResourceDataSeeder,
IGuidGenerator guidGenerator,
IPermissionDataSeeder permissionDataSeeder,
ICurrentTenant currentTenant)
{
_clientRepository = clientRepository;
_apiResourceRepository = apiResourceRepository;
_apiScopeRepository = apiScopeRepository;
_identityResourceDataSeeder = identityResourceDataSeeder;
_guidGenerator = guidGenerator;
_permissionDataSeeder = permissionDataSeeder;
_currentTenant = currentTenant;
}
[UnitOfWork]
public virtual async Task SeedAsync(DataSeedContext context)
{
using (_currentTenant.Change(context?.TenantId))
{
await _identityResourceDataSeeder.CreateStandardResourcesAsync();
await CreateApiResourcesAsync();
await CreateApiScopesAsync();
await CreateClientsAsync();
}
}
private async Task CreateApiScopesAsync()
{
await CreateApiScopeAsync();
}
private async Task CreateApiResourcesAsync()
{
var commonApiUserClaims = new[]
{
"email",
"email_verified",
"name",
"phone_number",
"phone_number_verified",
"role"
};
await CreateApiResourceAsync(commonApiUserClaims);
}
private async Task<ApiResource> CreateApiResourceAsync(IEnumerable<string> claims)
{
var apiResource = new ApiResource(
_guidGenerator.Create(),
"ApiResource_Test",
"单元测试"
);
return await _apiResourceRepository.InsertAsync(apiResource);
}
private async Task CreateApiScopeAsync()
{
await _apiScopeRepository.InsertAsync(
new ApiScope(
_guidGenerator.Create(),
"ApiScope_Test"
),
autoSave: true
);
}
private async Task CreateClientsAsync()
{
var client = await _clientRepository.FindByClientIdAsync("Test_Client");
if (client != null)
{
return;
}
var commonScopes = new[]
{
"email",
"openid",
"profile",
"role",
"phone",
"address",
};
await CreateClientAsync(
name: "Test_Client",
description: "单元测试",
scopes: commonScopes,
grantTypes: new[] { "implicit" },
secret: "1q2w3E*".Sha256(),
redirectUri: "http://localhost:4200/oidcSignIn",
postLogoutRedirectUri: "http://localhost:4200/oidcSignOut",
frontChannelLogoutUri: "http://localhost:4200/oidcSignOut",
corsOrigins: new[]
{
"http://localhost:4200"
},
requireClientSecret: false
);
}
private async Task<Client> CreateClientAsync(
string name,
string description,
IEnumerable<string> scopes,
IEnumerable<string> grantTypes,
string secret = null,
string redirectUri = null,
string postLogoutRedirectUri = null,
string frontChannelLogoutUri = null,
bool requireClientSecret = true,
bool requirePkce = false,
IEnumerable<string> permissions = null,
IEnumerable<string> corsOrigins = null)
{
var client = new Client(
_guidGenerator.Create(),
name
)
{
ClientName = name,
ProtocolType = "oidc",
Description = description,
AlwaysIncludeUserClaimsInIdToken = true,
AllowOfflineAccess = true,
AbsoluteRefreshTokenLifetime = 31536000, //365 days
AccessTokenLifetime = 31536000, //365 days
AuthorizationCodeLifetime = 300,
IdentityTokenLifetime = 300,
RequireConsent = false,
FrontChannelLogoutUri = frontChannelLogoutUri,
RequireClientSecret = requireClientSecret,
RequirePkce = requirePkce,
AllowAccessTokensViaBrowser = true,
};
foreach (var scope in scopes)
{
if (client.FindScope(scope) == null)
{
client.AddScope(scope);
}
}
foreach (var grantType in grantTypes)
{
if (client.FindGrantType(grantType) == null)
{
client.AddGrantType(grantType);
}
}
if (!secret.IsNullOrEmpty())
{
if (client.FindSecret(secret) == null)
{
client.AddSecret(secret);
}
}
if (redirectUri != null)
{
if (client.FindRedirectUri(redirectUri) == null)
{
client.AddRedirectUri(redirectUri);
}
}
if (postLogoutRedirectUri != null)
{
if (client.FindPostLogoutRedirectUri(postLogoutRedirectUri) == null)
{
client.AddPostLogoutRedirectUri(postLogoutRedirectUri);
}
}
if (permissions != null)
{
await _permissionDataSeeder.SeedAsync(
ClientPermissionValueProvider.ProviderName,
name,
permissions,
null
);
}
if (corsOrigins != null)
{
foreach (var origin in corsOrigins)
{
if (!origin.IsNullOrWhiteSpace() && client.FindCorsOrigin(origin) == null)
{
client.AddCorsOrigin(origin);
}
}
}
return await _clientRepository.InsertAsync(client);
}
}
}
Loading…
Cancel
Save