5
5
using System . Collections . Generic ;
6
6
using System . Reflection ;
7
7
using System . Threading . Tasks ;
8
- using Microsoft . AspNetCore . Components ;
8
+ using Microsoft . AspNetCore . Authorization ;
9
+ using Microsoft . AspNetCore . Components . Auth ;
10
+ using Microsoft . AspNetCore . Components . Internal ;
9
11
using Microsoft . AspNetCore . Components . Layouts ;
12
+ using Microsoft . AspNetCore . Components . RenderTree ;
10
13
11
14
namespace Microsoft . AspNetCore . Components
12
15
{
@@ -16,9 +19,6 @@ namespace Microsoft.AspNetCore.Components
16
19
/// </summary>
17
20
public class PageDisplay : IComponent
18
21
{
19
- internal const string NameOfPage = nameof ( Page ) ;
20
- internal const string NameOfPageParameters = nameof ( PageParameters ) ;
21
-
22
22
private RenderHandle _renderHandle ;
23
23
24
24
/// <summary>
@@ -34,6 +34,18 @@ public class PageDisplay : IComponent
34
34
[ Parameter ]
35
35
public IDictionary < string , object > PageParameters { get ; private set ; }
36
36
37
+ /// <summary>
38
+ /// The content that will be displayed if the user is not authorized.
39
+ /// </summary>
40
+ [ Parameter ]
41
+ public RenderFragment < AuthenticationState > NotAuthorizedContent { get ; private set ; }
42
+
43
+ /// <summary>
44
+ /// The content that will be displayed while asynchronous authorization is in progress.
45
+ /// </summary>
46
+ [ Parameter ]
47
+ public RenderFragment AuthorizingContent { get ; private set ; }
48
+
37
49
/// <inheritdoc />
38
50
public void Configure ( RenderHandle renderHandle )
39
51
{
@@ -50,41 +62,80 @@ public Task SetParametersAsync(ParameterCollection parameters)
50
62
51
63
private void Render ( )
52
64
{
53
- // In the middle, we render the requested page
54
- var fragment = RenderComponentWithBody ( Page , bodyParam : null ) ;
65
+ // In the middle goes the requested page
66
+ var fragment = ( RenderFragment ) RenderPageWithParameters ;
67
+
68
+ // Around that goes an AuthorizeViewCore
69
+ fragment = WrapInAuthorizeViewCore ( fragment ) ;
55
70
56
- // Repeatedly wrap it in each layer of nested layout until we get
71
+ // Then repeatedly wrap that in each layer of nested layout until we get
57
72
// to a layout that has no parent
58
73
Type layoutType = Page ;
59
74
while ( ( layoutType = GetLayoutType ( layoutType ) ) != null )
60
75
{
61
- fragment = RenderComponentWithBody ( layoutType , fragment ) ;
76
+ fragment = WrapInLayout ( layoutType , fragment ) ;
62
77
}
63
78
64
79
_renderHandle . Render ( fragment ) ;
65
80
}
66
81
67
- private RenderFragment RenderComponentWithBody ( Type componentType , RenderFragment bodyParam ) => builder =>
82
+ private RenderFragment WrapInLayout ( Type layoutType , RenderFragment bodyParam ) => builder =>
68
83
{
69
- builder . OpenComponent ( 0 , componentType ) ;
70
- if ( bodyParam != null )
71
- {
72
- builder . AddAttribute ( 1 , LayoutComponentBase . BodyPropertyName , bodyParam ) ;
73
- }
74
- else
84
+ builder . OpenComponent ( 0 , layoutType ) ;
85
+ builder . AddAttribute ( 1 , LayoutComponentBase . BodyPropertyName , bodyParam ) ;
86
+ builder . CloseComponent ( ) ;
87
+ } ;
88
+
89
+ private void RenderPageWithParameters ( RenderTreeBuilder builder )
90
+ {
91
+ builder . OpenComponent ( 0 , Page ) ;
92
+
93
+ if ( PageParameters != null )
75
94
{
76
- if ( PageParameters != null )
95
+ foreach ( var kvp in PageParameters )
77
96
{
78
- foreach ( var kvp in PageParameters )
79
- {
80
- builder . AddAttribute ( 1 , kvp . Key , kvp . Value ) ;
81
- }
97
+ builder . AddAttribute ( 1 , kvp . Key , kvp . Value ) ;
82
98
}
83
99
}
100
+
84
101
builder . CloseComponent ( ) ;
85
- } ;
102
+ }
103
+
104
+ private RenderFragment WrapInAuthorizeViewCore ( RenderFragment pageFragment )
105
+ {
106
+ var authorizeData = AttributeAuthorizeDataCache . GetAuthorizeDataForType ( Page ) ;
107
+ if ( authorizeData == null )
108
+ {
109
+ // No authorization, so no need to wrap the fragment
110
+ return pageFragment ;
111
+ }
86
112
87
- private Type GetLayoutType ( Type type )
113
+ // Some authorization data exists, so we do need to wrap the fragment
114
+ RenderFragment < AuthenticationState > authorizedContent = context => pageFragment ;
115
+ return builder =>
116
+ {
117
+ builder . OpenComponent < AuthorizeViewWithSuppliedData > ( 0 ) ;
118
+ builder . AddAttribute ( 1 , nameof ( AuthorizeViewWithSuppliedData . AuthorizeDataParam ) , authorizeData ) ;
119
+ builder . AddAttribute ( 2 , nameof ( AuthorizeViewWithSuppliedData . Authorized ) , authorizedContent ) ;
120
+ builder . AddAttribute ( 3 , nameof ( AuthorizeViewWithSuppliedData . NotAuthorized ) , NotAuthorizedContent ?? DefaultNotAuthorizedContent ) ;
121
+ builder . AddAttribute ( 4 , nameof ( AuthorizeViewWithSuppliedData . Authorizing ) , AuthorizingContent ) ;
122
+ builder . CloseComponent ( ) ;
123
+ } ;
124
+ }
125
+
126
+ private static Type GetLayoutType ( Type type )
88
127
=> type . GetCustomAttribute < LayoutAttribute > ( ) ? . LayoutType ;
128
+
129
+ private class AuthorizeViewWithSuppliedData : AuthorizeViewCore
130
+ {
131
+ [ Parameter ] public IAuthorizeData [ ] AuthorizeDataParam { get ; private set ; }
132
+
133
+ protected override IAuthorizeData [ ] AuthorizeData => AuthorizeDataParam ;
134
+ }
135
+
136
+ // There has to be some default content. If we render blank by default, developers
137
+ // will find it hard to guess why their UI isn't appearing.
138
+ private static RenderFragment DefaultNotAuthorizedContent ( AuthenticationState authenticationState )
139
+ => builder => builder . AddContent ( 0 , "Not authorized" ) ;
89
140
}
90
141
}
0 commit comments