11 changed files with 924 additions and 130 deletions
@ -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> |
|||
|
|||
@ -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> |
|||
@ -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()); |
|||
} |
|||
} |
|||
} |
|||
@ -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()); |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
} |
|||
@ -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()); |
|||
} |
|||
} |
|||
} |
|||
@ -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…
Reference in new issue