カスタムユーザーとの
イントロ
今回、私はBlazor(サーバー)アプリケーションから署名してみます.
環境
サンプル
ブレザーサーバに関する私のポスト
サイン
signinmanagerでの署名(失敗)
BlazorがDIを使うことができるので、私は最初にsigninmanagerに署名しようとしました.
ApplicationUserService。cs
...
public async Task<bool> SignInAsync(string email, string password)
{
var target = await applicationUsers.GetByEmailAsync(email);
if (target == null)
{
return false;
}
var result = await signInManager.PasswordSignInAsync(target, password, false, false);
return result.Succeeded;
}
...
signin剃刀
@page "/Pages/SignIn"
<div id="background">
<div id="sign_in_frame">
<h1>Sign In</h1>
<div class="sign_in_input_container">
<input type="text" @bind="Email" class="sign_in_input @AdditionalClassName">
</div>
<div class="sign_in_input_container">
<input type="password" @bind="Password" class="sign_in_input @AdditionalClassName">
</div>
<div id="sign_in_controller_container">
<button @onclick="StartSigningIn">Sign In</button>
</div>
</div>
</div>
signinかみそり。cs
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using ApprovementWorkflowSample.Applications;
namespace ApprovementWorkflowSample.Views
{
public partial class SignIn
{
[Inject]
public IJSRuntime? JSRuntime { get; init; }
[Inject]
public NavigationManager? Navigation { get; init; }
[Inject]
public IApplicationUserService? ApplicationUsers{get; init; }
[Parameter]
public string Email { get; set; } = "";
[Parameter]
public string Password { get; set; } = "";
[Parameter]
public string AdditionalClassName { get; set; } = "";
public async Task StartSigningIn()
{
if(string.IsNullOrEmpty(Email) ||
string.IsNullOrEmpty(Password))
{
await HandleSigningInFailedAsync("Email and Password are required");
return;
}
var result = await ApplicationUsers!.SignInAsync(Email, Password);
if(result)
{
Console.WriteLine("Navi");
Navigation!.NavigateTo("/Pages/Edit");
return;
}
AdditionalClassName = "login_failed";
await JSRuntime!.InvokeAsync<object>("Page.showAlert","Email or Password are not match");
}
private async Task HandleSigningInFailedAsync(string errorMessage)
{
AdditionalClassName = "login_failed";
await JSRuntime!.InvokeAsync<object>("Page.showAlert", errorMessage);
}
}
}
私は"signinasync "を呼び出して例外を得ました.Unhandled exception rendering component: Headers are read-only, response has already started. System.InvalidOperationException: Headers are read-only,
response has already started.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpHeaders.ThrowHeadersReadOnlyException()
...
コントローラからの署名(失敗)
それで、私はJavaScriptコードからサインインと同じようにコントローラからサインをしてみました.
ユーザーコントローラ。cs
...
[HttpPost]
[Route("Users/SignIn")]
public async ValueTask<bool> SignIn([FromBody]SignInValue value)
{
if(string.IsNullOrEmpty(value.Email) ||
string.IsNullOrEmpty(value.Password))
{
return false;
}
return await users.SignInAsync(value.Email, value.Password);
}
...
signinvalue。cs
namespace ApprovementWorkflowSample.Applications.Dto
{
public record SignInValue(string Email, string Password);
}
signinかみそり。cs
using System.IO;
using System.Text;
using System.Net.Http;
using System.Threading.Tasks;
using ApprovementWorkflowSample.Applications.Dto;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using Microsoft.Extensions.Configuration;
using ApprovementWorkflowSample.Applications;
using Newtonsoft.Json;
namespace ApprovementWorkflowSample.Views
{
public partial class SignIn
{
[Inject]
public IJSRuntime? JSRuntime { get; init; }
[Inject]
public IHttpClientFactory? HttpClients { get; init; }
[Inject]
public IConfiguration? Configuration { get; init; }
[Inject]
public NavigationManager? Navigation { get; init; }
...
public async Task StartSigningIn()
{
...
var httpClient = HttpClients.CreateClient();
var signInValue = new SignInValue(Email, Password);
var context = new StringContent(JsonConvert.SerializeObject(signInValue), Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(Path.Combine(Configuration!["BaseUrl"], "Users/SignIn"), context);
if(response.IsSuccessStatusCode == false)
{
await HandleSigningInFailedAsync("Failed access");
return;
}
string resultText = await response.Content.ReadAsStringAsync();
bool.TryParse(resultText, out var result);
if(result)
{
Navigation!.NavigateTo("/Pages/Edit");
return;
}
AdditionalClassName = "login_failed";
await HandleSigningInFailedAsync("Email or Password are not match");
}
...
私はどんな例外も得ませんでした、そして、私は結果として「真実」を得ることができました.しかし、ステータスは“認証”として扱われませんでした.
エディットワークフロー.剃刀
@page "/Pages/Edit"
@attribute [Authorize]
<CascadingAuthenticationState>
<AuthorizeView>
<Authorized>
<h1>Hello, @context.User.Identity!.Name!</h1>
<p>You can only see this content if you're authorized.</p>
</Authorized>
<NotAuthorized>
<h1>Authentication Failure!</h1>
<p>You're not signed in.</p>
</NotAuthorized>
</AuthorizeView>
</CascadingAuthenticationState>
認証された後に、このページは「noauthorizedされた」要素をまだ示しました.HTTP接続を通して認証されたので.しかし、サーバーサーバアプリケーションはsignalrを使用します.
それで、認証に関する情報を得ることができませんでした.
Regulsprincity , Requestentity , AuthenticationStatus ( OK )を使用する
スタックオーバーフローの記事によると、"iHostEnvironmentThenticationStateProvider "を追加し、"signin . razor . cs "を変更しました.
起動。cs
...
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<IHostEnvironmentAuthenticationStateProvider>(sp =>
(ServerAuthenticationStateProvider) sp.GetRequiredService<AuthenticationStateProvider>()
);
...
}
...
signinかみそり。cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using ApprovementWorkflowSample.Applications;
using Microsoft.AspNetCore.Identity;
using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Authentication.Cookies;
namespace ApprovementWorkflowSample.Views
{
public partial class SignIn
{
[Inject]
public IJSRuntime? JSRuntime { get; init; }
[Inject]
public NavigationManager? Navigation { get; init; }
[Inject]
public IApplicationUserService? ApplicationUsers{get; init; }
[Inject]
public SignInManager<ApplicationUser>? SignInManager { get; init; }
[Inject]
public IHostEnvironmentAuthenticationStateProvider? HostAuthentication { get; init; }
[Inject]
public AuthenticationStateProvider? AuthenticationStateProvider{get; init; }
...
public async Task StartSigningIn()
{
...
ApplicationUser? user = await ApplicationUsers!.GetUserByEmailAsync(Email);
if(user == null)
{
await HandleSigningInFailedAsync("Email or Password are not match");
return;
}
SignInResult loginResult = await SignInManager!.CheckPasswordSignInAsync(user, Password, false);
if(loginResult.Succeeded == false)
{
await HandleSigningInFailedAsync("Email or Password are not match");
return;
}
if(loginResult.Succeeded)
{
ClaimsPrincipal principal = await SignInManager.CreateUserPrincipalAsync(user);
SignInManager.Context.User = principal;
HostAuthentication!.SetAuthenticationState(
Task.FromResult(new AuthenticationState(principal)));
// If you don't need doing anything without moving to next page, you can remove this.
AuthenticationState authState = await AuthenticationStateProvider!.GetAuthenticationStateAsync();
Navigation!.NavigateTo("/Pages/Edit");
}
}
...
最後に、私はサインすることができました、そして、ステータスは「認証された」として扱われました.非認証ユーザーの自動リダイレクト
ASP .NETコアMVCは、ユーザーが認証されていないときに自動的にリダイレクトできます.
ブレザーはどう?
今回はこのポストに続きました.
アプリ。剃刀
@using Shared
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
<RedirectToSignIn></RedirectToSignIn>
</NotAuthorized>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
redirecttosignin。かみそり。cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
namespace ApprovementWorkflowSample.Views
{
public partial class RedirectToSignIn
{
[CascadingParameter]
private Task<AuthenticationState>? AuthenticationStateTask { get; init; }
[Inject]
public NavigationManager? Navigation { get; init; }
protected override async Task OnInitializedAsync()
{
var authenticationState = await AuthenticationStateTask!;
if (authenticationState?.User?.Identity is null || !authenticationState.User.Identity.IsAuthenticated)
{
var returnUrl = Navigation!.ToBaseRelativePath(Navigation.Uri);
if (string.IsNullOrWhiteSpace(returnUrl))
{
Navigation.NavigateTo("Pages/SignIn", true);
}
else
{
Navigation.NavigateTo($"Pages/SignIn?returnUrl={returnUrl}", true);
}
}
}
}
}
資源
Reference
この問題について(カスタムユーザーとの), 我々は、より多くの情報をここで見つけました https://dev.to/masanori_msl/blazor-server-signin-with-custom-user-2e74テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol