実現したいこと
[実現したい事]※BlazorとAsp.netが初心者です
blazor webassemblyアプリケーションで、
1.ログインしていない時、未認証状態にする。
2.ログインが成功した時にAuthorizeViewを認証状態にする。
[実装した内容]
<前準備>
1.AuthenticationStateProviderを継承したクラスを作成。(CustomeAuthticateProviderという名前で作成)
2.Program.csにbuilder.Services.AddScopedを使用して、手順1で作成したクラスを登録。
(この時、AddAuthorizationCoreやAddCascadingAuthenticationStateも呼び出しています)
<ログインから認証状態の流れ>
1.画面表示。
(この状態では未認証。最初の画面表示時、自作したCustomeAuthticateProviderクラスのGetAuthenticationStateAsyncが呼び出され、未認証状態なので、空のAuthenticationStateを返しておく)
2.ログインする。ログイン時に、自作で作成したWEB APIを呼び出し、呼び出し結果からWEB API側で作成した、JWTのトークンを取得する。
3.ログイン時に使用したユーザーIDとJWTのトークンを、ブラウザ側のセッションストレージに保存する。
4.CustomeAuthticateProviderクラスから、NotifyAuthenticationStateChangedメソッドを実行する。
この時、引数には手順3でセッションストレージに保存したユーザーIDをClaimsIdentityに含めた、AuthenticationStateを渡す。
(NotifyAuthenticationStateChangedメソッドは、継承元のAuthenticationStateProviderクラスで定義されているメソッド)
5.認証状態に変更なし(AuthorizeViewを使用しているどのページに移動しても変化なし)
発生している問題・分からないこと
[わからない事]
AuthorizeView認証状態の更新方法がわかりません。
[発生している問題]
AuthenticationStateProviderのNotifyAuthenticationStateChangedメソッドを呼び出しても、認証状態が更新されないです。
[デバッグ時の状況]
AuthenticationStateProviderクラスのNotifyAuthenticationStateChangedを何度も実行しても、AuthenticationStateProviderのGetAuthenticationStateAsyncがAuthorizeView側から呼ばれません。(この時、AuthenticationStateProviderクラスのAuthenticationStateChangedイベントは呼ばれますが、肝心のAuthorizeViewの状態は更新されません。)
該当のソースコード
C#
1using BlazorApp1; 2using Microsoft.AspNetCore.Components.Authorization; 3using Microsoft.AspNetCore.Components.Web; 4using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 5using Blazored.SessionStorage; 6using Microsoft.AspNetCore.Authorization; 7using Microsoft.Extensions.Options; 8 9var builder = WebAssemblyHostBuilder.CreateDefault(args); 10builder.RootComponents.Add<App>("#app"); 11builder.RootComponents.Add<HeadOutlet>("head::after"); 12 13builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); 14 15// ブラウザ側のセッションストレージを使用する為に 16// NuGetでインストールしたBlazored.SessionStorage(2.4.0)を使用 17builder.Services.AddBlazoredSessionStorage(); 18 19// 自作で作成したAuthenticationStateProviderを継承したクラスを登録 20builder.Services.AddScoped<AuthenticationStateProvider, CustomeAuthticateProvider>(); 21 22// 自作で定義したインターフェースの登録。 23builder.Services.AddScoped<ICustomeAuthticateProvider, CustomeAuthticateProvider>(); 24// 自作のサービスクラスを登録 25builder.Services.AddScoped<IAuthService, CustomeAuthService>(); 26 27builder.Services.AddAuthorizationCore(); 28 29builder.Services.AddCascadingAuthenticationState(); 30 31await builder.Build().RunAsync(); 32
c#
1using Microsoft.AspNetCore.Components.Authorization; 2using Microsoft.AspNetCore.Components; 3using System.Security.Claims; 4using System.Net.Http.Headers; 5using Blazored.SessionStorage; 6 7namespace BlazorApp1; 8 9public interface ICustomeAuthticateProvider 10{ 11 public Task MarkUserAsAuthenticated(string userID, string authToken); 12 13 public Task MarkUserAsLoggedOut(); 14 15 public void ExecuteNotifyAuthenticationStateChanged(); 16} 17 18internal class CustomeAuthticateProvider : AuthenticationStateProvider, ICustomeAuthticateProvider 19{ 20 private readonly HttpClient _httpClient; 21 22 private readonly ISessionStorageService _sessionStorageService; 23 24 public CustomeAuthticateProvider(HttpClient httpClient, ISessionStorageService sessionStorageService) 25 { 26 _httpClient = httpClient; 27 _sessionStorageService = sessionStorageService; 28 base.AuthenticationStateChanged += CustomeAuthticateProvider_AuthenticationStateChanged; 29 } 30 31 private async void CustomeAuthticateProvider_AuthenticationStateChanged(Task<AuthenticationState> task) 32 { 33 var state = await task; 34 if (state != null) 35 { 36 string name = state.User.Identity?.Name ?? ""; 37 Console.WriteLine($"呼ばれたよ!!======= name={name}"); 38 } 39 } 40 41 public async override Task<AuthenticationState> GetAuthenticationStateAsync() 42 { 43 // ローカルストレージからトークンとユーザ名を取得 44 var savedToken = await _sessionStorageService.GetItemAsync<string>("authToken"); 45 var userID = await _sessionStorageService.GetItemAsync<string>("userID"); 46 47 if (string.IsNullOrWhiteSpace(savedToken)) 48 { 49 return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); 50 } 51 52 _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", savedToken); 53 54 var identity = new ClaimsIdentity( 55 [ 56 new Claim(ClaimTypes.Name, userID), 57 ], "Test"); 58 var principal = new ClaimsPrincipal(identity); 59 var authenticationState = new AuthenticationState(principal); 60 return authenticationState; 61 62 } 63 64 public async Task MarkUserAsAuthenticated(string userID, string authToken) 65 { 66 // ローカルストレージに認証情報を保持して変更通知を行う 67 await _sessionStorageService.SetItemAsync("userID", userID); 68 await _sessionStorageService.SetItemAsync("authToken", authToken); 69 70 NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); 71 } 72 73 public async Task MarkUserAsLoggedOut() 74 { 75 // ローカルストレージの認証情報を削除して変更通知を行う 76 await _sessionStorageService.RemoveItemAsync("userID"); 77 await _sessionStorageService.RemoveItemAsync("authToken"); 78 if (_httpClient.DefaultRequestHeaders.Authorization != null) 79 { 80 _httpClient.DefaultRequestHeaders.Authorization = null; 81 } 82 NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); 83 } 84 85 public void ExecuteNotifyAuthenticationStateChanged() 86 { 87 NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); 88 } 89}
c#
1using Microsoft.AspNetCore.Authorization; 2 3namespace BlazorApp1 4{ 5 public class TestAuthHandler : AuthorizationHandler<TestRequirement> 6 { 7 protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TestRequirement requirement) 8 { 9 //context.Succeed(requirement); 10 //context.Fail(); 11 12 var identityName = context.User.Identity?.Name; 13 if (identityName is null) 14 { 15 context.Fail(); 16 return Task.CompletedTask; 17 } 18 19 context.Succeed(requirement); 20 21 return Task.CompletedTask; 22 } 23 } 24} 25 26
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
[他に試したこと]
ポリシーを追加して、そのポリシーに対応したIAuthorizationHandlerを実装したクラスのHandleRequirementAsyncメソッドの引数のAuthorizationHandlerContextに、どのような値が入ってきているか確認
<手順>
1.前準備として、Program.csの中で、builder.Services.AddAuthorizationCoreの引数のアクション内で、"Test"という名前でconfigure.AddPolicyメソッドを実行しポリシーを作成し。
2.builder.Services.AddScoped<IAuthorizationHandler, TestAuthHandler>();という一行を追加して、TestAuthHandlerクラスが、AuthorizeViewでポリシーに"Test"を設定している場合、表示時に呼ばれるように設定。
<確認内容>
1.AuthorizeViewの初期画面表示時は、AuthorizationHandlerContextに何も設定されていないものが設定されていた。
2.ログインしてブラウザ側のセッションストレージにユーザーIDなどを保存し、AuthenticationStateProviderクラスのNotifyAuthenticationStateChangedを呼び出しても、AuthenticationStateProviderクラスのGetAuthenticationStateAsyncメソッドが呼び出されない為、AuthorizationHandlerContextの中身は空のままです。
補足
[使用しているツールやバージョン]
Microsoft Visual Studio Community 2022 (64 ビット) (Version 17.12.3)
プロジェクトの.netのターゲット:net9.0
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。