mirror of
https://gitee.com/ant-design-blazor/ant-design-blazor.git
synced 2024-11-29 18:48:50 +08:00
feat(module: tabs): Add AuthorizeReuseTabsRouteView (#1910)
* 使MenItem同时支持Icon和IconFont,解决当使用iconfont.cn图标后,缩起内嵌菜单导致按钮样式不统一的问题。 * 空值判断 * add IconTemplate in MenuItem * code format * Add AuthorizeReuseTabsRouteView * add readme.md * remove comments * Add AuthorizeResuseTabsRouteView test demo * save * save * done * refactor the test app * fix test app * debug * debug * fix tab render * fix the copyright * fix package infomation * fix tab display order * fix content focerender Co-authored-by: BG345554 <ymgu@best-inc.com> Co-authored-by: James Yeung <shunjiey@hotmail.com>
This commit is contained in:
parent
5c2f48f718
commit
cc836bcf10
1
.github/workflows/nightly-build.yml
vendored
1
.github/workflows/nightly-build.yml
vendored
@ -87,6 +87,7 @@ jobs:
|
||||
dotnet build
|
||||
dotnet pack components/AntDesign.csproj /p:PackageVersion=${FULL_VERSION} -c Release -o publish
|
||||
dotnet pack tests/AntDesign.TestKit/AntDesign.TestKit.csproj /p:PackageVersion=${FULL_VERSION} -c Release -o publish
|
||||
dotnet pack src/AntDesign.Components.Authentication/AntDesign.Components.Authentication.csproj /p:PackageVersion=${FULL_VERSION} -c Release -o publish
|
||||
env:
|
||||
next_version: ${{ steps.get_next_version.outputs.next_version }}
|
||||
|
||||
|
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@ -39,6 +39,7 @@ jobs:
|
||||
dotnet build
|
||||
dotnet pack components/AntDesign.csproj /p:PackageVersion=$VERSION -c Release -o publish
|
||||
dotnet pack tests/AntDesign.TestKit/AntDesign.TestKit.csproj /p:PackageVersion=$VERSION -c Release -o publish
|
||||
dotnet pack src/AntDesign.Components.Authentication/AntDesign.Components.Authentication.csproj /p:PackageVersion=$VERSION -c Release -o publish
|
||||
dotnet nuget push publish/*.nupkg -s https://api.nuget.org/v3/index.json -k $NUGET_API_KEY --skip-duplicate
|
||||
|
||||
- name: Upload package artifact
|
||||
|
@ -35,9 +35,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntDesign.Tests", "tests\An
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{DFD13180-D1BF-44DA-BEBE-4A54EFDEFFE2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AntDesign.Tests.Js", "tests\AntDesign.Tests.Js\AntDesign.Tests.Js.csproj", "{3C4ADCD5-6879-4478-9BA5-28C894AD52F3}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntDesign.Tests.Js", "tests\AntDesign.Tests.Js\AntDesign.Tests.Js.csproj", "{3C4ADCD5-6879-4478-9BA5-28C894AD52F3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AntDesign.Docs.Build", "site\AntDesign.Docs.Build\AntDesign.Docs.Build.csproj", "{67E9D6C5-106F-412C-B43C-F096145FD8A9}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntDesign.Docs.Build", "site\AntDesign.Docs.Build\AntDesign.Docs.Build.csproj", "{67E9D6C5-106F-412C-B43C-F096145FD8A9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntDesign.Components.Authentication", "src\AntDesign.Components.Authentication\AntDesign.Components.Authentication.csproj", "{88E00D83-912A-4AC4-9A6D-34F87DC3A675}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AntDesign.TestApp", "AntDesign.TestApp", "{606789E3-AFE9-4489-9963-2B06A701D6B6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntDesign.TestApp.Server", "tests\AntDesign.TestApp\Server\AntDesign.TestApp.Server.csproj", "{32A251DB-FF95-4325-B80F-0E3B0FA5CBC5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntDesign.TestApp.Client", "tests\AntDesign.TestApp\Client\AntDesign.TestApp.Client.csproj", "{5ADDB648-9417-4FE9-8A7D-0D4BF2DD3EC5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -77,14 +85,26 @@ Global
|
||||
{51D7507D-48BA-43BB-8223-CE35A2D7D0D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{51D7507D-48BA-43BB-8223-CE35A2D7D0D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{51D7507D-48BA-43BB-8223-CE35A2D7D0D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{67E9D6C5-106F-412C-B43C-F096145FD8A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{67E9D6C5-106F-412C-B43C-F096145FD8A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{67E9D6C5-106F-412C-B43C-F096145FD8A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{67E9D6C5-106F-412C-B43C-F096145FD8A9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3C4ADCD5-6879-4478-9BA5-28C894AD52F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3C4ADCD5-6879-4478-9BA5-28C894AD52F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3C4ADCD5-6879-4478-9BA5-28C894AD52F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3C4ADCD5-6879-4478-9BA5-28C894AD52F3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{67E9D6C5-106F-412C-B43C-F096145FD8A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{67E9D6C5-106F-412C-B43C-F096145FD8A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{67E9D6C5-106F-412C-B43C-F096145FD8A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{67E9D6C5-106F-412C-B43C-F096145FD8A9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{88E00D83-912A-4AC4-9A6D-34F87DC3A675}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{88E00D83-912A-4AC4-9A6D-34F87DC3A675}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{88E00D83-912A-4AC4-9A6D-34F87DC3A675}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{88E00D83-912A-4AC4-9A6D-34F87DC3A675}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{32A251DB-FF95-4325-B80F-0E3B0FA5CBC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{32A251DB-FF95-4325-B80F-0E3B0FA5CBC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{32A251DB-FF95-4325-B80F-0E3B0FA5CBC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{32A251DB-FF95-4325-B80F-0E3B0FA5CBC5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5ADDB648-9417-4FE9-8A7D-0D4BF2DD3EC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5ADDB648-9417-4FE9-8A7D-0D4BF2DD3EC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5ADDB648-9417-4FE9-8A7D-0D4BF2DD3EC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5ADDB648-9417-4FE9-8A7D-0D4BF2DD3EC5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -98,8 +118,12 @@ Global
|
||||
{5A765767-0766-433D-B78D-97D8F29CA6A6} = {D34F1DE5-ECF7-4CF0-8325-B7A38F41D376}
|
||||
{7193BE83-12C1-4B35-8197-C28D20FBA1E6} = {DFD13180-D1BF-44DA-BEBE-4A54EFDEFFE2}
|
||||
{51D7507D-48BA-43BB-8223-CE35A2D7D0D8} = {DFD13180-D1BF-44DA-BEBE-4A54EFDEFFE2}
|
||||
{67E9D6C5-106F-412C-B43C-F096145FD8A9} = {D34F1DE5-ECF7-4CF0-8325-B7A38F41D376}
|
||||
{3C4ADCD5-6879-4478-9BA5-28C894AD52F3} = {DFD13180-D1BF-44DA-BEBE-4A54EFDEFFE2}
|
||||
{67E9D6C5-106F-412C-B43C-F096145FD8A9} = {D34F1DE5-ECF7-4CF0-8325-B7A38F41D376}
|
||||
{88E00D83-912A-4AC4-9A6D-34F87DC3A675} = {C60BCE84-4AF4-4393-8D3E-1B69E29549C1}
|
||||
{606789E3-AFE9-4489-9963-2B06A701D6B6} = {DFD13180-D1BF-44DA-BEBE-4A54EFDEFFE2}
|
||||
{32A251DB-FF95-4325-B80F-0E3B0FA5CBC5} = {606789E3-AFE9-4489-9963-2B06A701D6B6}
|
||||
{5ADDB648-9417-4FE9-8A7D-0D4BF2DD3EC5} = {606789E3-AFE9-4489-9963-2B06A701D6B6}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E124DDCB-1F8D-4F96-BF41-D87019D0A412}
|
||||
|
@ -2,18 +2,21 @@
|
||||
@inherits AntDomComponentBase
|
||||
|
||||
<Tabs Class="@Class" Style="@Style" Id="@Id" HideAdd Type="@TabType.EditableCard" @bind-ActiveKey="@CurrentUrl" OnClose="RemovePage">
|
||||
@foreach (var item in Pages)
|
||||
@if (Pages != null)
|
||||
{
|
||||
<TabPane @key="@item.Url" Key="@item.Url" Class="@TabPaneClass" Closable ForceRender>
|
||||
<TabTemplate>
|
||||
@item.Title
|
||||
</TabTemplate>
|
||||
<ChildContent>
|
||||
@if (Body != null)
|
||||
{
|
||||
@Body(item)
|
||||
}
|
||||
</ChildContent>
|
||||
</TabPane>
|
||||
@foreach (var item in Pages)
|
||||
{
|
||||
<TabPane @key="@item.Url" Key="@item.Url" Class="@TabPaneClass" Closable ForceRender>
|
||||
<TabTemplate>
|
||||
@item.Title
|
||||
</TabTemplate>
|
||||
<ChildContent>
|
||||
@if (Body != null)
|
||||
{
|
||||
@Body(item)
|
||||
}
|
||||
</ChildContent>
|
||||
</TabPane>
|
||||
}
|
||||
}
|
||||
</Tabs>
|
||||
|
@ -16,7 +16,7 @@ namespace AntDesign
|
||||
[CascadingParameter(Name = "RouteView")]
|
||||
public ReuseTabsRouteView RouteView { get; set; }
|
||||
|
||||
internal ReuseTabsPageItem[] Pages => RouteView.Pages;
|
||||
internal ReuseTabsPageItem[] Pages => RouteView?.Pages;
|
||||
|
||||
protected string CurrentUrl
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
@ -6,6 +7,8 @@ namespace AntDesign
|
||||
{
|
||||
public string Url { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
public RenderFragment Title { get; set; }
|
||||
|
||||
public RenderFragment Body { get; set; }
|
||||
|
@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AntDesign
|
||||
{
|
||||
@ -19,12 +20,22 @@ namespace AntDesign
|
||||
|
||||
private string CurrentUrl => Navmgr.Uri;
|
||||
|
||||
internal ReuseTabsPageItem[] Pages => _pageMap.Values.ToArray();
|
||||
internal ReuseTabsPageItem[] Pages => _pageMap.Values.OrderBy(x => x.CreatedAt).ToArray();
|
||||
|
||||
public void RemovePage(string key)
|
||||
{
|
||||
_pageMap.Remove(key);
|
||||
}
|
||||
public void RemovePageWithRegex(string pattern)
|
||||
{
|
||||
foreach (var key in _pageMap.Keys)
|
||||
{
|
||||
if (Regex.IsMatch(key, pattern))
|
||||
{
|
||||
_pageMap.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ReplaceBody(string key, RenderFragment body)
|
||||
{
|
||||
@ -50,7 +61,6 @@ namespace AntDesign
|
||||
builder.AddAttribute(3, "ChildContent", (RenderFragment)(b =>
|
||||
{
|
||||
b.OpenComponent(20, layoutType);
|
||||
b.AddAttribute(21, "Body", body);
|
||||
b.CloseComponent();
|
||||
}));
|
||||
}
|
||||
@ -63,6 +73,7 @@ namespace AntDesign
|
||||
{
|
||||
Body = body,
|
||||
Url = CurrentUrl,
|
||||
CreatedAt = DateTime.Now,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
@if (_hasClosed)
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
@if (IsTab)
|
||||
@ -12,18 +12,18 @@
|
||||
var onclickStopPropagation = !_isActive;
|
||||
|
||||
<div @key="Key"
|
||||
@ref="_tabRef"
|
||||
@onclick:stopPropagation="@onclickStopPropagation"
|
||||
@onclick="@(e => Parent.HandleTabClick(this))"
|
||||
@ondragover:preventDefault="@ondragoverPreventDefault"
|
||||
@ondragstart="@(e => Parent.HandleDragStart(e, this))"
|
||||
@ondrop="@(_ => Parent.HandleDrop(this))"
|
||||
aria-controls="@($"rc-tabs-{Id}-tab-{Key}")"
|
||||
aria-selected="@(_isActive)"
|
||||
class="@ClassMapper.Class"
|
||||
draggable="@Parent.Draggable.ToString()"
|
||||
id="@($"rc-tabs-{Id}-tab-{Key}")"
|
||||
ondragover="event.preventDefault();">
|
||||
@ref="_tabRef"
|
||||
@onclick:stopPropagation="@onclickStopPropagation"
|
||||
@onclick="@(e => Parent.HandleTabClick(this))"
|
||||
@ondragover:preventDefault="@ondragoverPreventDefault"
|
||||
@ondragstart="@(e => Parent.HandleDragStart(e, this))"
|
||||
@ondrop="@(_ => Parent.HandleDrop(this))"
|
||||
aria-controls="@($"rc-tabs-{Id}-tab-{Key}")"
|
||||
aria-selected="@(_isActive)"
|
||||
class="@ClassMapper.Class"
|
||||
draggable="@Parent.Draggable.ToString()"
|
||||
id="@($"rc-tabs-{Id}-tab-{Key}")"
|
||||
ondragover="event.preventDefault();">
|
||||
<div role="tab" aria-selected="false" class="ant-tabs-tab-btn" tabindex="0">
|
||||
@if (TabTemplate != null)
|
||||
{
|
||||
@ -45,16 +45,16 @@
|
||||
else if (IsPane)
|
||||
{
|
||||
<div @key="Key"
|
||||
tabindex="@(_isActive ? "0" : "-1")"
|
||||
class="ant-tabs-tabpane @(_isActive ? "ant-tabs-tabpane-active" : "")"
|
||||
id="@($"rc-tabs-{Id}-panel-{Key}")"
|
||||
role="tabpanel" aria-hidden="@(_isActive ? "false" : "true")"
|
||||
aria-labelledby="@($"rc-tabs-{Id}-panel-{Key}")"
|
||||
style="@(_isActive || Parent.Animated ? "" : "display: none;")">
|
||||
@if (_isActive || _hasRendered || ForceRender)
|
||||
{
|
||||
_hasRendered = true;
|
||||
@ChildContent
|
||||
}
|
||||
tabindex="@(_isActive ? "0" : "-1")"
|
||||
class="ant-tabs-tabpane @(_isActive ? "ant-tabs-tabpane-active" : "")"
|
||||
id="@($"rc-tabs-{Id}-panel-{Key}")"
|
||||
role="tabpanel" aria-hidden="@(_isActive ? "false" : "true")"
|
||||
aria-labelledby="@($"rc-tabs-{Id}-panel-{Key}")"
|
||||
style="@(_isActive || Parent.Animated ? "" : "display: none;")">
|
||||
@if (_isActive || _hasRendered || ForceRender)
|
||||
{
|
||||
_hasRendered = true;
|
||||
@ChildContent
|
||||
}
|
||||
</div>
|
||||
}
|
@ -52,6 +52,8 @@ namespace AntDesign
|
||||
public bool Closable { get; set; } = true;
|
||||
internal bool IsActive => _isActive;
|
||||
|
||||
private bool HasTabTitle => Tab != null || TabTemplate != null;
|
||||
|
||||
internal ElementReference TabRef => _tabRef;
|
||||
|
||||
private const string PrefixCls = "ant-tabs-tab";
|
||||
@ -76,6 +78,11 @@ namespace AntDesign
|
||||
{
|
||||
base.OnAfterRender(firstRender);
|
||||
|
||||
if (IsTab && HasTabTitle)
|
||||
{
|
||||
_hasRendered = true;
|
||||
}
|
||||
|
||||
_shouldRender = false;
|
||||
_shouldTabRender = false;
|
||||
}
|
||||
@ -84,15 +91,18 @@ namespace AntDesign
|
||||
{
|
||||
base.OnParametersSet();
|
||||
_shouldRender = true;
|
||||
_shouldTabRender = true;
|
||||
}
|
||||
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
// Avoid changes in tab as we modify the properties used for display when drag and drop occurs
|
||||
if (!IsTab)
|
||||
if (IsTab && _hasRendered)
|
||||
{
|
||||
await base.SetParametersAsync(parameters);
|
||||
return;
|
||||
}
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
}
|
||||
|
||||
private void SetClass()
|
||||
|
@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.1;net5</TargetFrameworks>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<OutputType>Library</OutputType>
|
||||
<IsPackable>true</IsPackable>
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
<Description>🌈 An authentication extensions components for Ant Design Blazor library. </Description>
|
||||
<PackageProjectUrl>https://github.com/ant-design-blazor/ant-design-blazor</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/ant-design-blazor/ant-design-blazor</RepositoryUrl>
|
||||
<PackageTags>blazor,ant-design,antd,design,razor,components</PackageTags>
|
||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<Copyright>.NET Foundation and Contributors</Copyright>
|
||||
<Authors>James Yeung</Authors>
|
||||
<PackageIcon>logo.png</PackageIcon>
|
||||
<NoWarn>CA2007</NoWarn>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="$(TargetFramework) == 'netstandard2.1'">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="3.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net5'">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\components\AntDesign.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,54 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace AntDesign.Components.Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is copy from the official repo.
|
||||
/// source: https://github.com/dotnet/aspnetcore/blob/main/src/Components/Authorization/src/AttributeAuthorizeDataCache.cs
|
||||
/// </summary>
|
||||
internal static class AttributeAuthorizeDataCache
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, IAuthorizeData[]?> _cache = new ConcurrentDictionary<Type, IAuthorizeData[]?>();
|
||||
|
||||
public static IAuthorizeData[]? GetAuthorizeDataForType(Type type)
|
||||
{
|
||||
if (!_cache.TryGetValue(type, out var result))
|
||||
{
|
||||
result = ComputeAuthorizeDataForType(type);
|
||||
_cache[type] = result; // Safe race - doesn't matter if it overwrites
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IAuthorizeData[]? ComputeAuthorizeDataForType(Type type)
|
||||
{
|
||||
// Allow Anonymous skips all authorization
|
||||
var allAttributes = type.GetCustomAttributes(inherit: true);
|
||||
List<IAuthorizeData>? authorizeDatas = null;
|
||||
for (var i = 0; i < allAttributes.Length; i++)
|
||||
{
|
||||
if (allAttributes[i] is IAllowAnonymous)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (allAttributes[i] is IAuthorizeData authorizeData)
|
||||
{
|
||||
authorizeDatas ??= new List<IAuthorizeData>();
|
||||
authorizeDatas.Add(authorizeData);
|
||||
}
|
||||
}
|
||||
|
||||
return authorizeDatas?.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
|
||||
namespace AntDesign.Components.Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is modify from the official AuthorizeRouteView.cs
|
||||
/// source: https://github.com/dotnet/aspnetcore/blob/main/src/Components/Authorization/src/AuthorizeRouteView.cs
|
||||
///
|
||||
/// Combines the behaviors of <see cref="AuthorizeView"/> and <see cref="RouteView"/>,
|
||||
/// so that it displays the page matching the specified route but only if the user
|
||||
/// is authorized to see it.
|
||||
///
|
||||
/// Additionally, this component supplies a cascading parameter of type <see cref="Task{AuthenticationState}"/>,
|
||||
/// which makes the user's current authentication state available to descendants.
|
||||
/// </summary>
|
||||
public sealed class AuthorizeReuseTabsRouteView : ReuseTabsRouteView
|
||||
{
|
||||
// We expect applications to supply their own authorizing/not-authorized content, but
|
||||
// it's better to have defaults than to make the parameters mandatory because in some
|
||||
// cases they will never be used (e.g., "authorizing" in out-of-box server-side Blazor)
|
||||
private static readonly RenderFragment<AuthenticationState> _defaultNotAuthorizedContent
|
||||
= state => builder => builder.AddContent(0, "Not authorized");
|
||||
private static readonly RenderFragment _defaultAuthorizingContent
|
||||
= builder => builder.AddContent(0, "Authorizing...");
|
||||
|
||||
private readonly RenderFragment _renderAuthorizeRouteViewCoreDelegate;
|
||||
private readonly RenderFragment<AuthenticationState> _renderAuthorizedDelegate;
|
||||
private readonly RenderFragment<AuthenticationState> _renderNotAuthorizedDelegate;
|
||||
private readonly RenderFragment _renderAuthorizingDelegate;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of a <see cref="AuthorizeRouteView"/>.
|
||||
/// </summary>
|
||||
public AuthorizeReuseTabsRouteView()
|
||||
{
|
||||
// Cache the rendering delegates so that we only construct new closure instances
|
||||
// when they are actually used (e.g., we never prepare a RenderFragment bound to
|
||||
// the NotAuthorized content except when you are displaying that particular state)
|
||||
RenderFragment renderBaseRouteViewDelegate = builder => base.Render(builder);
|
||||
_renderAuthorizedDelegate = authenticateState => renderBaseRouteViewDelegate;
|
||||
_renderNotAuthorizedDelegate = authenticationState => builder => RenderNotAuthorizedInDefaultLayout(builder, authenticationState);
|
||||
_renderAuthorizingDelegate = RenderAuthorizingInDefaultLayout;
|
||||
_renderAuthorizeRouteViewCoreDelegate = RenderAuthorizeRouteViewCore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The content that will be displayed if the user is not authorized.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment<AuthenticationState>? NotAuthorized { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The content that will be displayed while asynchronous authorization is in progress.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment? Authorizing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The resource to which access is being controlled.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public object? Resource { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
private Task<AuthenticationState>? ExistingCascadedAuthenticationState { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Render(RenderTreeBuilder builder)
|
||||
{
|
||||
if (ExistingCascadedAuthenticationState != null)
|
||||
{
|
||||
// If this component is already wrapped in a <CascadingAuthenticationState> (or another
|
||||
// compatible provider), then don't interfere with the cascaded authentication state.
|
||||
_renderAuthorizeRouteViewCoreDelegate(builder);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, implicitly wrap the output in a <CascadingAuthenticationState>
|
||||
builder.OpenComponent<CascadingAuthenticationState>(0);
|
||||
builder.AddAttribute(1, nameof(CascadingAuthenticationState.ChildContent), _renderAuthorizeRouteViewCoreDelegate);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderAuthorizeRouteViewCore(RenderTreeBuilder builder)
|
||||
{
|
||||
builder.OpenComponent<AuthorizeRouteViewCore>(0);
|
||||
builder.AddAttribute(1, nameof(AuthorizeRouteViewCore.RouteData), RouteData);
|
||||
builder.AddAttribute(2, nameof(AuthorizeRouteViewCore.Authorized), _renderAuthorizedDelegate);
|
||||
builder.AddAttribute(3, nameof(AuthorizeRouteViewCore.Authorizing), _renderAuthorizingDelegate);
|
||||
builder.AddAttribute(4, nameof(AuthorizeRouteViewCore.NotAuthorized), _renderNotAuthorizedDelegate);
|
||||
builder.AddAttribute(5, nameof(AuthorizeRouteViewCore.Resource), Resource);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
|
||||
//[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2111:RequiresUnreferencedCode",
|
||||
// Justification = "OpenComponent already has the right set of attributes")]
|
||||
//[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2110:RequiresUnreferencedCode",
|
||||
// Justification = "OpenComponent already has the right set of attributes")]
|
||||
private void RenderContentInDefaultLayout(RenderTreeBuilder builder, RenderFragment content)
|
||||
{
|
||||
builder.OpenComponent<LayoutView>(0);
|
||||
builder.AddAttribute(1, nameof(LayoutView.Layout), DefaultLayout);
|
||||
builder.AddAttribute(2, nameof(LayoutView.ChildContent), content);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
|
||||
private void RenderNotAuthorizedInDefaultLayout(RenderTreeBuilder builder, AuthenticationState authenticationState)
|
||||
{
|
||||
var content = NotAuthorized ?? _defaultNotAuthorizedContent;
|
||||
RenderContentInDefaultLayout(builder, content(authenticationState));
|
||||
}
|
||||
|
||||
private void RenderAuthorizingInDefaultLayout(RenderTreeBuilder builder)
|
||||
{
|
||||
var content = Authorizing ?? _defaultAuthorizingContent;
|
||||
RenderContentInDefaultLayout(builder, content);
|
||||
}
|
||||
|
||||
private sealed class AuthorizeRouteViewCore : AuthorizeViewCore
|
||||
{
|
||||
[Parameter]
|
||||
public RouteData RouteData { get; set; } = default!;
|
||||
|
||||
protected override IAuthorizeData[]? GetAuthorizeData()
|
||||
=> AttributeAuthorizeDataCache.GetAuthorizeDataForType(RouteData.PageType);
|
||||
}
|
||||
}
|
||||
}
|
63
src/AntDesign.Components.Authentication/README.md
Normal file
63
src/AntDesign.Components.Authentication/README.md
Normal file
@ -0,0 +1,63 @@
|
||||
# AuthorizeReuseTabsRouteView
|
||||
|
||||
A combination of `ReuseTabsRouteView` and `AuthorizeRouteView`.
|
||||
|
||||
|
||||
|
||||
# How to use
|
||||
|
||||
Almost the same as `AuthorizeRouteView`.
|
||||
|
||||
|
||||
|
||||
1. Modify the `App.razor` file, replace the `RouteView` or `ReuseTabsRouteView` with `AuthorizeReuseTabsRouteView`.
|
||||
|
||||
```diff
|
||||
+<CascadingAuthenticationState>
|
||||
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
|
||||
<Found Context="routeData">
|
||||
- <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
|
||||
+ <AuthorizeReuseTabsRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
|
||||
+ <NotAuthorized>
|
||||
+ <RedirectToLogin />
|
||||
+ </NotAuthorized>
|
||||
+ <Authorizing>
|
||||
+ <p>Authorizing............</p>
|
||||
+ </Authorizing>
|
||||
+ </AuthorizeReuseTabsRouteView>
|
||||
</Found>
|
||||
<NotFound>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<p>Sorry, there's nothing at this address.</p>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
+</CascadingAuthenticationState>
|
||||
```
|
||||
|
||||
2. Then modify the `MainLayout.razor` file, add the `ReuseTabs` component. Note that `@Body` is **required** at this case, so you can perform redirect and other actions.
|
||||
|
||||
```diff
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<div class="page">
|
||||
<div class="sidebar">
|
||||
<NavMenu />
|
||||
</div>
|
||||
|
||||
<div class="main">
|
||||
- <div class="top-row px-4">
|
||||
- <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
|
||||
- </div>
|
||||
<div class="content px-4">
|
||||
@Body
|
||||
</div>
|
||||
+ <ReuseTabs Class="top-row px-4" TabPaneClass="content px-4" / >
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```
|
||||
|
||||
# Customize tab title
|
||||
|
||||
Same as `ReuseTabsRouteView`
|
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.9" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="5.0.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\components\AntDesign.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\AntDesign.Components.Authentication\AntDesign.Components.Authentication.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
26
tests/AntDesign.TestApp/Client/App.razor
Normal file
26
tests/AntDesign.TestApp/Client/App.razor
Normal file
@ -0,0 +1,26 @@
|
||||
<CascadingAuthenticationState>
|
||||
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
|
||||
<Found Context="routeData">
|
||||
<AntDesign.Components.Authentication.AuthorizeReuseTabsRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
|
||||
<NotAuthorized>
|
||||
@if (!context.User.Identity.IsAuthenticated)
|
||||
{
|
||||
<RedirectToLogin />
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>You are not authorized to access this resource.</p>
|
||||
}
|
||||
</NotAuthorized>
|
||||
</AntDesign.Components.Authentication.AuthorizeReuseTabsRouteView>
|
||||
</Found>
|
||||
<NotFound>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<p>Sorry, there's nothing at this address.</p>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
</CascadingAuthenticationState>
|
||||
|
||||
|
||||
<AntContainer />
|
17
tests/AntDesign.TestApp/Client/Data/WeatherForecast.cs
Normal file
17
tests/AntDesign.TestApp/Client/Data/WeatherForecast.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AntDesign.TestApp.Client.Data
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public string Summary { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
}
|
||||
}
|
25
tests/AntDesign.TestApp/Client/Pages/Authentication.razor
Normal file
25
tests/AntDesign.TestApp/Client/Pages/Authentication.razor
Normal file
@ -0,0 +1,25 @@
|
||||
@page "/authentication/{action}"
|
||||
|
||||
@attribute [ReuseTabsPageTitle("Authentication")]
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
|
||||
|
||||
<RemoteAuthenticatorView Action="@Action" OnLogInSucceeded="OnLogInSucceed" OnLogOutSucceeded="OnLogOutSucceed" />
|
||||
|
||||
@code{
|
||||
|
||||
[Parameter] public string Action { get; set; }
|
||||
|
||||
[CascadingParameter(Name = "RouteView")]
|
||||
public ReuseTabsRouteView RouteView { get; set; }
|
||||
|
||||
private void OnLogInSucceed(RemoteAuthenticationState state)
|
||||
{
|
||||
this.RouteView?.RemovePageWithRegex("/authentication/");
|
||||
}
|
||||
|
||||
private void OnLogOutSucceed(RemoteAuthenticationState state)
|
||||
{
|
||||
this.RouteView?.RemovePageWithRegex("/authentication/");
|
||||
state.ReturnUrl = "/";
|
||||
}
|
||||
}
|
23
tests/AntDesign.TestApp/Client/Pages/Counter.razor
Normal file
23
tests/AntDesign.TestApp/Client/Pages/Counter.razor
Normal file
@ -0,0 +1,23 @@
|
||||
@page "/counter/{id}"
|
||||
@inherits ComponentBase
|
||||
@implements IReuseTabsPage
|
||||
|
||||
<h1>Counter @Id</h1>
|
||||
|
||||
<p>Current count: @currentCount</p>
|
||||
|
||||
<Button Type="primary" @onclick="IncrementCount">Click me</Button>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter ] public string Id { get; set; }
|
||||
|
||||
private int currentCount = 0;
|
||||
|
||||
public RenderFragment GetPageTitle() =>@<span>@($"Counter {Id}")</span>;
|
||||
|
||||
private void IncrementCount()
|
||||
{
|
||||
currentCount++;
|
||||
}
|
||||
}
|
58
tests/AntDesign.TestApp/Client/Pages/FetchData.razor
Normal file
58
tests/AntDesign.TestApp/Client/Pages/FetchData.razor
Normal file
@ -0,0 +1,58 @@
|
||||
@page "/fetchdata"
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
|
||||
@using AntDesign.TestApp.Client.Data
|
||||
@attribute [Authorize]
|
||||
@inject HttpClient Http
|
||||
@attribute [ReuseTabsPageTitle("Fetchdata")]
|
||||
|
||||
<h1>Weather forecast</h1>
|
||||
|
||||
<p>This component demonstrates fetching data from the server.</p>
|
||||
|
||||
@if (forecasts == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var forecast in forecasts)
|
||||
{
|
||||
<tr>
|
||||
<td>@forecast.Date.ToShortDateString()</td>
|
||||
<td>@forecast.TemperatureC</td>
|
||||
<td>@forecast.TemperatureF</td>
|
||||
<td>@forecast.Summary</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
@code {
|
||||
private WeatherForecast[] forecasts;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
|
||||
}
|
||||
catch (AccessTokenNotAvailableException exception)
|
||||
{
|
||||
Console.WriteLine("--------------->" + exception.Message);
|
||||
exception.Redirect();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
7
tests/AntDesign.TestApp/Client/Pages/Index.razor
Normal file
7
tests/AntDesign.TestApp/Client/Pages/Index.razor
Normal file
@ -0,0 +1,7 @@
|
||||
@page "/"
|
||||
@attribute [ReuseTabsPageTitle("Index")]
|
||||
<h1>Hello, world!</h1>
|
||||
|
||||
Welcome to your new app.
|
||||
|
||||
<SurveyPrompt Title="How is Blazor working for you?" />
|
34
tests/AntDesign.TestApp/Client/Program.cs
Normal file
34
tests/AntDesign.TestApp/Client/Program.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntDesign.TestApp.Client
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
builder.RootComponents.Add<App>("#app");
|
||||
|
||||
builder.Services.AddHttpClient("AntDesign.TestApp.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
|
||||
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
|
||||
|
||||
// Supply HttpClient instances that include access tokens when making requests to the server project
|
||||
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("AntDesign.TestApp.ServerAPI"));
|
||||
|
||||
builder.Services.AddApiAuthorization();
|
||||
|
||||
builder.Services.AddAntDesign();
|
||||
|
||||
await builder.Build().RunAsync();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:57346",
|
||||
"sslPort": 44322
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"AntDesign.Tests.Authentication": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": "true",
|
||||
"launchBrowser": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
tests/AntDesign.TestApp/Client/Shared/LoginDisplay.razor
Normal file
24
tests/AntDesign.TestApp/Client/Shared/LoginDisplay.razor
Normal file
@ -0,0 +1,24 @@
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
|
||||
|
||||
@inject NavigationManager Navigation
|
||||
@inject SignOutSessionStateManager SignOutManager
|
||||
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<a href="authentication/profile">Hello, @context.User.Identity.Name!</a>
|
||||
<button class="nav-link btn btn-link" @onclick="BeginSignOut">Log out</button>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<a href="authentication/register">Register</a>
|
||||
<a href="authentication/login">Log in</a>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
|
||||
@code{
|
||||
private async Task BeginSignOut(MouseEventArgs args)
|
||||
{
|
||||
await SignOutManager.SetSignOutState();
|
||||
Navigation.NavigateTo("authentication/logout");
|
||||
}
|
||||
}
|
31
tests/AntDesign.TestApp/Client/Shared/MainLayout.razor
Normal file
31
tests/AntDesign.TestApp/Client/Shared/MainLayout.razor
Normal file
@ -0,0 +1,31 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<Layout Style="height: 100vh;">
|
||||
<Sider Collapsible Collapsed=@collapsed NoTrigger>
|
||||
<div class="logo" />
|
||||
<NavMenu />
|
||||
</Sider>
|
||||
<Layout>
|
||||
<Header>
|
||||
<LoginDisplay />
|
||||
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
|
||||
</Header>
|
||||
<Content>
|
||||
@Body
|
||||
<div>
|
||||
<ReuseTabs />
|
||||
</div>
|
||||
</Content>
|
||||
<Footer>Footer</Footer>
|
||||
</Layout>
|
||||
</Layout>
|
||||
|
||||
@code
|
||||
{
|
||||
bool collapsed;
|
||||
|
||||
void toggle()
|
||||
{
|
||||
collapsed = !collapsed;
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
.logo {
|
||||
height: 32px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
margin: 16px;
|
||||
}
|
7
tests/AntDesign.TestApp/Client/Shared/NavMenu.razor
Normal file
7
tests/AntDesign.TestApp/Client/Shared/NavMenu.razor
Normal file
@ -0,0 +1,7 @@
|
||||
<Menu Theme="MenuTheme.Dark">
|
||||
<MenuItem Title="Home" Icon="home" RouterLink="" RouterMatch="NavLinkMatch.All" />
|
||||
<MenuItem Title="Counter 1" Icon="plus" RouterLink="counter/1" RouterMatch="NavLinkMatch.Prefix" />
|
||||
<MenuItem Title="Counter 2" Icon="plus" RouterLink="counter/2" RouterMatch="NavLinkMatch.Prefix" />
|
||||
<MenuItem Title="Counter 3" Icon="plus" RouterLink="counter/3" RouterMatch="NavLinkMatch.Prefix" />
|
||||
<MenuItem Title="Fetch" Icon="unordered-list" RouterLink="fetchdata" RouterMatch="NavLinkMatch.All"/>
|
||||
</Menu>
|
@ -0,0 +1,9 @@
|
||||
@inject NavigationManager Navigation
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
|
||||
|
||||
@code {
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Navigation.NavigateTo($"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
|
||||
}
|
||||
}
|
16
tests/AntDesign.TestApp/Client/Shared/SurveyPrompt.razor
Normal file
16
tests/AntDesign.TestApp/Client/Shared/SurveyPrompt.razor
Normal file
@ -0,0 +1,16 @@
|
||||
<div class="alert alert-secondary mt-4" role="alert">
|
||||
<span class="oi oi-pencil mr-2" aria-hidden="true"></span>
|
||||
<strong>@Title</strong>
|
||||
|
||||
<span class="text-nowrap">
|
||||
Please take our
|
||||
<a target="_blank" class="font-weight-bold" href="https://go.microsoft.com/fwlink/?linkid=2137916">brief survey</a>
|
||||
</span>
|
||||
and tell us what you think.
|
||||
</div>
|
||||
|
||||
@code {
|
||||
// Demonstrates how a parent component can supply parameters
|
||||
[Parameter]
|
||||
public string Title { get; set; }
|
||||
}
|
12
tests/AntDesign.TestApp/Client/_Imports.razor
Normal file
12
tests/AntDesign.TestApp/Client/_Imports.razor
Normal file
@ -0,0 +1,12 @@
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Http
|
||||
@using Microsoft.JSInterop
|
||||
@using AntDesign.TestApp.Client
|
||||
@using AntDesign.TestApp.Client.Shared
|
||||
@using AntDesign
|
49
tests/AntDesign.TestApp/Client/wwwroot/css/app.css
Normal file
49
tests/AntDesign.TestApp/Client/wwwroot/css/app.css
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
html, body {
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
a, .btn-link {
|
||||
color: #0366d6;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1.1rem;
|
||||
}
|
||||
|
||||
.valid.modified:not([type=checkbox]) {
|
||||
outline: 1px solid #26b050;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
outline: 1px solid red;
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
background: lightyellow;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||
display: none;
|
||||
left: 0;
|
||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#blazor-error-ui .dismiss {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 0.5rem;
|
||||
}
|
BIN
tests/AntDesign.TestApp/Client/wwwroot/favicon.ico
Normal file
BIN
tests/AntDesign.TestApp/Client/wwwroot/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
28
tests/AntDesign.TestApp/Client/wwwroot/index.html
Normal file
28
tests/AntDesign.TestApp/Client/wwwroot/index.html
Normal file
@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<title>AntDesign.Tests.Authentication</title>
|
||||
<base href="/" />
|
||||
|
||||
<link href="css/app.css" rel="stylesheet" />
|
||||
<link href="AntDesign.TestApp.Client.styles.css" rel="stylesheet" />
|
||||
<link href="_content/AntDesign/css/ant-design-blazor.css" rel="stylesheet">
|
||||
<script src="_content/AntDesign/js/ant-design-blazor.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">Loading...</div>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
|
||||
<script src="_framework/blazor.webassembly.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<UserSecretsId>AntDesign.Tests.Authentication.Server-60788253-21B9-4F6A-87BD-B31690EE5806</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="5.0.9" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Client\AntDesign.TestApp.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="5.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="5.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="5.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.9" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,35 @@
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using AntDesign.TestApp.Server.Models
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
@{
|
||||
var returnUrl = "/";
|
||||
if (Context.Request.Query.TryGetValue("returnUrl", out var existingUrl)) {
|
||||
returnUrl = existingUrl;
|
||||
}
|
||||
}
|
||||
|
||||
<ul class="navbar-nav">
|
||||
@if (SignInManager.IsSignedIn(User))
|
||||
{
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello @User.Identity.Name!</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="/" method="post">
|
||||
<button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
|
||||
</form>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register" asp-route-returnUrl="@returnUrl">Register</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login" asp-route-returnUrl="@returnUrl">Login</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
@ -0,0 +1,26 @@
|
||||
using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace AntDesign.TestApp.Server.Controllers
|
||||
{
|
||||
public class OidcConfigurationController : Controller
|
||||
{
|
||||
private readonly ILogger<OidcConfigurationController> _logger;
|
||||
|
||||
public OidcConfigurationController(IClientRequestParametersProvider clientRequestParametersProvider, ILogger<OidcConfigurationController> logger)
|
||||
{
|
||||
ClientRequestParametersProvider = clientRequestParametersProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public IClientRequestParametersProvider ClientRequestParametersProvider { get; }
|
||||
|
||||
[HttpGet("_configuration/{clientId}")]
|
||||
public IActionResult GetClientRequestParameters([FromRoute] string clientId)
|
||||
{
|
||||
var parameters = ClientRequestParametersProvider.GetClientParameters(HttpContext, clientId);
|
||||
return Ok(parameters);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
using AntDesign.TestApp.Client.Data;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntDesign.TestApp.Server.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class WeatherForecastController : ControllerBase
|
||||
{
|
||||
private static readonly string[] _summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
private readonly ILogger<WeatherForecastController> _logger;
|
||||
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IEnumerable<WeatherForecast> Get()
|
||||
{
|
||||
var rng = new Random();
|
||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = DateTime.Now.AddDays(index),
|
||||
TemperatureC = rng.Next(-20, 55),
|
||||
Summary = _summaries[rng.Next(_summaries.Length)]
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
21
tests/AntDesign.TestApp/Server/Data/ApplicationDbContext.cs
Normal file
21
tests/AntDesign.TestApp/Server/Data/ApplicationDbContext.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using AntDesign.TestApp.Server.Models;
|
||||
using IdentityServer4.EntityFramework.Options;
|
||||
using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntDesign.TestApp.Server.Data
|
||||
{
|
||||
public class ApplicationDbContext : ApiAuthorizationDbContext<ApplicationUser>
|
||||
{
|
||||
public ApplicationDbContext(
|
||||
DbContextOptions options,
|
||||
IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
380
tests/AntDesign.TestApp/Server/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
generated
Normal file
380
tests/AntDesign.TestApp/Server/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
generated
Normal file
@ -0,0 +1,380 @@
|
||||
// <auto-generated />
|
||||
using AntDesign.TestApp.Server.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using System;
|
||||
|
||||
namespace AntDesign.TestApp.Server.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("00000000000000_CreateIdentitySchema")]
|
||||
partial class CreateIdentitySchema
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseIdentityColumns()
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||
.HasAnnotation("ProductVersion", "5.0.0-rc.1.20417.2");
|
||||
|
||||
modelBuilder.Entity("AntDesign.TestApp.Server.Models.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("datetimeoffset");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b =>
|
||||
{
|
||||
b.Property<string>("UserCode")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50000)
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("DeviceCode")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<DateTime?>("Expiration")
|
||||
.IsRequired()
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("SessionId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("SubjectId")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.HasKey("UserCode");
|
||||
|
||||
b.HasIndex("DeviceCode")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Expiration");
|
||||
|
||||
b.ToTable("DeviceCodes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<DateTime?>("ConsumedTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50000)
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<DateTime?>("Expiration")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("SessionId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("SubjectId")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.HasIndex("Expiration");
|
||||
|
||||
b.HasIndex("SubjectId", "ClientId", "Type");
|
||||
|
||||
b.HasIndex("SubjectId", "SessionId", "Type");
|
||||
|
||||
b.ToTable("PersistedGrants");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.UseIdentityColumn();
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.UseIdentityColumn();
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("AntDesign.TestApp.Server.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("AntDesign.TestApp.Server.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("AntDesign.TestApp.Server.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("AntDesign.TestApp.Server.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,290 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
|
||||
namespace AntDesign.TestApp.Server.Data.Migrations
|
||||
{
|
||||
public partial class CreateIdentitySchema : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoles",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
NormalizedName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(type: "nvarchar(max)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUsers",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
UserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
NormalizedUserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
Email = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
NormalizedEmail = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
EmailConfirmed = table.Column<bool>(type: "bit", nullable: false),
|
||||
PasswordHash = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
SecurityStamp = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
PhoneNumber = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
PhoneNumberConfirmed = table.Column<bool>(type: "bit", nullable: false),
|
||||
TwoFactorEnabled = table.Column<bool>(type: "bit", nullable: false),
|
||||
LockoutEnd = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true),
|
||||
LockoutEnabled = table.Column<bool>(type: "bit", nullable: false),
|
||||
AccessFailedCount = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "DeviceCodes",
|
||||
columns: table => new
|
||||
{
|
||||
UserCode = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
DeviceCode = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
SubjectId = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
|
||||
SessionId = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
ClientId = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
Expiration = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
Data = table.Column<string>(type: "nvarchar(max)", maxLength: 50000, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_DeviceCodes", x => x.UserCode);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PersistedGrants",
|
||||
columns: table => new
|
||||
{
|
||||
Key = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
Type = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
SubjectId = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
|
||||
SessionId = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
ClientId = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
Expiration = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
ConsumedTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
Data = table.Column<string>(type: "nvarchar(max)", maxLength: 50000, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PersistedGrants", x => x.Key);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoleClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
RoleId = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
ClaimValue = table.Column<string>(type: "nvarchar(max)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
ClaimValue = table.Column<string>(type: "nvarchar(max)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserLogins",
|
||||
columns: table => new
|
||||
{
|
||||
LoginProvider = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
|
||||
ProviderKey = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
|
||||
ProviderDisplayName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserRoles",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
RoleId = table.Column<string>(type: "nvarchar(450)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserTokens",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
LoginProvider = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
|
||||
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
|
||||
Value = table.Column<string>(type: "nvarchar(max)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetRoleClaims_RoleId",
|
||||
table: "AspNetRoleClaims",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "RoleNameIndex",
|
||||
table: "AspNetRoles",
|
||||
column: "NormalizedName",
|
||||
unique: true,
|
||||
filter: "[NormalizedName] IS NOT NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserClaims_UserId",
|
||||
table: "AspNetUserClaims",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserLogins_UserId",
|
||||
table: "AspNetUserLogins",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserRoles_RoleId",
|
||||
table: "AspNetUserRoles",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "EmailIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedEmail");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "UserNameIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedUserName",
|
||||
unique: true,
|
||||
filter: "[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DeviceCodes_DeviceCode",
|
||||
table: "DeviceCodes",
|
||||
column: "DeviceCode",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DeviceCodes_Expiration",
|
||||
table: "DeviceCodes",
|
||||
column: "Expiration");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PersistedGrants_Expiration",
|
||||
table: "PersistedGrants",
|
||||
column: "Expiration");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PersistedGrants_SubjectId_ClientId_Type",
|
||||
table: "PersistedGrants",
|
||||
columns: new[] { "SubjectId", "ClientId", "Type" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PersistedGrants_SubjectId_SessionId_Type",
|
||||
table: "PersistedGrants",
|
||||
columns: new[] { "SubjectId", "SessionId", "Type" });
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoleClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserLogins");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "DeviceCodes");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PersistedGrants");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUsers");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,378 @@
|
||||
// <auto-generated />
|
||||
using AntDesign.TestApp.Server.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using System;
|
||||
|
||||
namespace AntDesign.TestApp.Server.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseIdentityColumns()
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||
.HasAnnotation("ProductVersion", "5.0.0-rc.1.20417.2");
|
||||
|
||||
modelBuilder.Entity("AntDesign.TestApp.Server.Models.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("datetimeoffset");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b =>
|
||||
{
|
||||
b.Property<string>("UserCode")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50000)
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("DeviceCode")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<DateTime?>("Expiration")
|
||||
.IsRequired()
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("SessionId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("SubjectId")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.HasKey("UserCode");
|
||||
|
||||
b.HasIndex("DeviceCode")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Expiration");
|
||||
|
||||
b.ToTable("DeviceCodes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<DateTime?>("ConsumedTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50000)
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<DateTime?>("Expiration")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("SessionId")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("SubjectId")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.HasIndex("Expiration");
|
||||
|
||||
b.HasIndex("SubjectId", "ClientId", "Type");
|
||||
|
||||
b.HasIndex("SubjectId", "SessionId", "Type");
|
||||
|
||||
b.ToTable("PersistedGrants");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.UseIdentityColumn();
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.UseIdentityColumn();
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("AntDesign.TestApp.Server.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("AntDesign.TestApp.Server.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("AntDesign.TestApp.Server.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("AntDesign.TestApp.Server.Models.ApplicationUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
12
tests/AntDesign.TestApp/Server/Models/ApplicationUser.cs
Normal file
12
tests/AntDesign.TestApp/Server/Models/ApplicationUser.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntDesign.TestApp.Server.Models
|
||||
{
|
||||
public class ApplicationUser : IdentityUser
|
||||
{
|
||||
}
|
||||
}
|
42
tests/AntDesign.TestApp/Server/Pages/Error.cshtml
Normal file
42
tests/AntDesign.TestApp/Server/Pages/Error.cshtml
Normal file
@ -0,0 +1,42 @@
|
||||
@page
|
||||
@model AntDesign.TestApp.Server.Pages.ErrorModel
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<title>Error</title>
|
||||
<link href="~/css/bootstrap/bootstrap.min.css" rel="stylesheet" />
|
||||
<link href="~/css/app.css" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="main">
|
||||
<div class="content px-4">
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (Model.ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
32
tests/AntDesign.TestApp/Server/Pages/Error.cshtml.cs
Normal file
32
tests/AntDesign.TestApp/Server/Pages/Error.cshtml.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntDesign.TestApp.Server.Pages
|
||||
{
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
[IgnoreAntiforgeryToken]
|
||||
public class ErrorModel : PageModel
|
||||
{
|
||||
public string RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
private readonly ILogger<ErrorModel> _logger;
|
||||
|
||||
public ErrorModel(ILogger<ErrorModel> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
26
tests/AntDesign.TestApp/Server/Program.cs
Normal file
26
tests/AntDesign.TestApp/Server/Program.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntDesign.TestApp.Server
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:57346",
|
||||
"sslPort": 44322
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"AntDesign.TestApp.Server": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": "true",
|
||||
"launchBrowser": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"mssql1": {
|
||||
"type": "mssql",
|
||||
"connectionId": "ConnectionStrings:DefaultConnection"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"mssql1": {
|
||||
"type": "mssql.local",
|
||||
"connectionId": "ConnectionStrings:DefaultConnection"
|
||||
}
|
||||
}
|
||||
}
|
82
tests/AntDesign.TestApp/Server/Startup.cs
Normal file
82
tests/AntDesign.TestApp/Server/Startup.cs
Normal file
@ -0,0 +1,82 @@
|
||||
using AntDesign.TestApp.Server.Data;
|
||||
using AntDesign.TestApp.Server.Models;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
using Microsoft.AspNetCore.ResponseCompression;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System.Linq;
|
||||
|
||||
namespace AntDesign.TestApp.Server
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseSqlServer(
|
||||
Configuration.GetConnectionString("DefaultConnection")));
|
||||
|
||||
services.AddDatabaseDeveloperPageExceptionFilter();
|
||||
|
||||
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
|
||||
services.AddIdentityServer()
|
||||
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
|
||||
|
||||
services.AddAuthentication()
|
||||
.AddIdentityServerJwt();
|
||||
|
||||
services.AddControllersWithViews();
|
||||
services.AddRazorPages();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseMigrationsEndPoint();
|
||||
app.UseWebAssemblyDebugging();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseBlazorFrameworkFiles();
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseIdentityServer();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapRazorPages();
|
||||
endpoints.MapControllers();
|
||||
endpoints.MapFallbackToFile("index.html");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
14
tests/AntDesign.TestApp/Server/appsettings.Development.json
Normal file
14
tests/AntDesign.TestApp/Server/appsettings.Development.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"IdentityServer": {
|
||||
"Key": {
|
||||
"Type": "Development"
|
||||
}
|
||||
}
|
||||
}
|
20
tests/AntDesign.TestApp/Server/appsettings.json
Normal file
20
tests/AntDesign.TestApp/Server/appsettings.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-AntDesign.Tests.Authentication;Trusted_Connection=True;MultipleActiveResultSets=true"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"IdentityServer": {
|
||||
"Clients": {
|
||||
"AntDesign.TestApp.Client": {
|
||||
"Profile": "IdentityServerSPA"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
Loading…
Reference in New Issue
Block a user