1
1
using BlazorServerCaptureUser . Areas . Identity ;
2
2
using BlazorServerCaptureUser . Data ;
3
- using Microsoft . AspNetCore . Components ;
4
3
using Microsoft . AspNetCore . Components . Authorization ;
5
- using Microsoft . AspNetCore . Components . Web ;
4
+ using Microsoft . AspNetCore . Components . Server . Circuits ;
6
5
using Microsoft . AspNetCore . Identity ;
7
- using Microsoft . AspNetCore . Identity . UI ;
8
6
using Microsoft . EntityFrameworkCore ;
7
+ using Microsoft . Extensions . DependencyInjection . Extensions ;
8
+ using System . Security . Claims ;
9
9
10
10
var builder = WebApplication . CreateBuilder ( args ) ;
11
11
21
21
builder . Services . AddScoped < AuthenticationStateProvider , RevalidatingIdentityAuthenticationStateProvider < IdentityUser > > ( ) ;
22
22
builder . Services . AddSingleton < WeatherForecastService > ( ) ;
23
23
24
+ builder . Services . AddScoped < UserService > ( ) ;
25
+ builder . Services . TryAddEnumerable ( ServiceDescriptor . Scoped < CircuitHandler , UserCircuitHandler > ( ) ) ;
26
+
24
27
var app = builder . Build ( ) ;
25
28
26
29
// Configure the HTTP request pipeline.
48
51
app . MapFallbackToPage ( "/_Host" ) ;
49
52
50
53
app . Run ( ) ;
54
+
55
+ public class UserService
56
+ {
57
+ private ClaimsPrincipal _currentUser = new ClaimsPrincipal ( new ClaimsIdentity ( ) ) ;
58
+
59
+ public ClaimsPrincipal GetUser ( )
60
+ {
61
+ return _currentUser ;
62
+ }
63
+
64
+ internal void SetUser ( ClaimsPrincipal user )
65
+ {
66
+ // This might be called more than once
67
+ if ( _currentUser != user )
68
+ {
69
+ _currentUser = user ;
70
+ }
71
+ }
72
+ }
73
+
74
+ internal sealed class UserCircuitHandler : CircuitHandler , IDisposable
75
+ {
76
+ private readonly AuthenticationStateProvider _authenticationStateProvider ;
77
+ private readonly UserService _userService ;
78
+
79
+ public UserCircuitHandler (
80
+ AuthenticationStateProvider authenticationStateProvider ,
81
+ UserService userService )
82
+ {
83
+ _authenticationStateProvider = authenticationStateProvider ;
84
+ _userService = userService ;
85
+ }
86
+
87
+ public void Dispose ( )
88
+ {
89
+ _authenticationStateProvider . AuthenticationStateChanged -= AuthenticationChanged ;
90
+ }
91
+
92
+ // This and the method below are only needed if you want to update the user after the app has re-connected.
93
+ public override Task OnCircuitOpenedAsync ( Circuit circuit , CancellationToken cancellationToken )
94
+ {
95
+ // If you want to update the service, then you can attach an event handler as follows
96
+ _authenticationStateProvider . AuthenticationStateChanged += AuthenticationChanged ;
97
+ return base . OnCircuitOpenedAsync ( circuit , cancellationToken ) ;
98
+ }
99
+
100
+ private void AuthenticationChanged ( Task < AuthenticationState > task )
101
+ {
102
+ _ = UpdateAuthentication ( task ) ;
103
+
104
+ async Task UpdateAuthentication ( Task < AuthenticationState > task )
105
+ {
106
+ try
107
+ {
108
+ var state = await task ;
109
+ _userService . SetUser ( state . User ) ;
110
+ }
111
+ catch
112
+ {
113
+ // Swallow all exceptions here since there is no way to report them
114
+ // (and if they come from the task, they'll be reported somewhere else).
115
+ }
116
+ }
117
+ }
118
+
119
+ public override async Task OnConnectionUpAsync ( Circuit circuit , CancellationToken cancellationToken )
120
+ {
121
+ // This gets called every time the circuit reconnects, setting the user for the lifetime of the connection.
122
+ // Unless you implement updates.
123
+ var state = await _authenticationStateProvider . GetAuthenticationStateAsync ( ) ;
124
+ _userService . SetUser ( state . User ) ;
125
+ }
126
+ }
0 commit comments