本文介绍了如何通过IdentityServer4将OpenIdConnect添加到ASP.NET Core ServerSide Blazor Web应用程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我执行了以下操作(它应该可以工作,但是不行),没有重定向,没有错误,没有任何问题,它只显示没有身份验证的页面,我在做什么错了?

I did the following (It should work but it does not), no redirect, no error, no nothing, it just displays the page without auth, what am I doing wrong?

第1步.安装Microsoft.AspNetCore.Authentication.OpenIdConnect包

Step 1. Install-Package Microsoft.AspNetCore.Authentication.OpenIdConnect

第2步.编辑Statup.cs

Step 2. Edit Statup.cs

在"ConfigurationServices"下添加

Under "ConfigurationServices" add

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
        {
           options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
           options.Authority = "http://localhost:5000";
           options.RequireHttpsMetadata = false; //false for development only
           options.ClientId = "mywebclient";
           options.ResponseType = "code";
           options.UsePkce = true;
           options.Scope.Add("profile");
           options.Scope.Add("offline_access");
           options.SaveTokens = true;
        });

在配置"下添加

        ...
        services.AddAuthorization();

        app.UseStaticFiles();

        app.UseRouting();


        app.UseAuthentication();
        app.UseAuthorization();

        ....

第3步.添加属性授权到blazor页面"

Step 3. Add attribute Authorize to blazor page

        @page "/item"
        @attribute [Authorize] 

推荐答案

您的代码遇到了两个弊端...主要问题是您的代码没有提供身份验证质询请求机制,该机制无法重定向到身份验证代理,例如IdentityServer.这仅可通过HttpContext来实现,而HttpContext在SignalR(Blazor Server应用程序)中不可用.为了解决这个问题,我们将在HttpContext可用的地方添加几个Razor页面.答案中有更多...

Your code suffers from a couple of maladies... The main issue is that your code provides no authentication challenge request mechanism that enables redirection to an authenticating agent such as IdentityServer. This is only possible with HttpContext, which is not available in SignalR (Blazor Server App). To solve this issue we'll add a couple of Razor pages where the HttpContext is available. More in the answer...

以下是该问题的完整且可行的解决方案:

The following is a complete and working solution to the question:

  1. 创建Blazor服务器应用程序.
  2. 安装软件包Microsoft.AspNetCore.Authentication.OpenIdConnect-版本3.1.0
  3. 创建一个名为LoginDisplay(LoginDisplay.razor)的组件,并将其放置在Shared文件夹中.该组件用于MainLayout组件

  1. Create a Blazor Server App.
  2. Install-Package Microsoft.AspNetCore.Authentication.OpenIdConnect -Version 3.1.0
  3. Create a component named LoginDisplay (LoginDisplay.razor), and place it in the Shared folder. This component is used in the MainLayout component

<AuthorizeView> <Authorized> <a href="logout">Hello, @context.User.Identity.Name !</a> <form method="get" action="logout"> <button type="submit" class="nav-link btn btn-link">Log out</button> </form> </Authorized> <NotAuthorized> <a href="login?redirectUri=/">Log in</a> </NotAuthorized></AuthorizeView>

<AuthorizeView> <Authorized> <a href="logout">Hello, @context.User.Identity.Name !</a> <form method="get" action="logout"> <button type="submit" class="nav-link btn btn-link">Log out</button> </form> </Authorized> <NotAuthorized> <a href="login?redirectUri=/">Log in</a> </NotAuthorized></AuthorizeView>

将LoginDisplay组件添加到MainLayout组件中,位于About的正上方锚元素,像这样<div class="top-row px-4"> <LoginDisplay /> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a></div>

Add the LoginDisplay component to the MainLayout component, just above the Aboutanchor element, like this<div class="top-row px-4"> <LoginDisplay /> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a></div>

注意:为了将登录和注销请求重定向到IdentityServer,我们必须创建两个Razor页面,如下所示:1.创建一个登录剃刀"页面Login.cshtml(Login.cshtml.cs),并将其放置在Pages文件夹中,如下所示:

Note: In order to redirect requests for login and for logout to IdentityServer, we have to create two Razor pages as follows:1. Create a Login Razor page Login.cshtml (Login.cshtml.cs) and place them in the Pages folder as follow:

using Microsoft.AspNetCore.Authentication;
 using Microsoft.AspNetCore.Authentication.OpenIdConnect;
 using Microsoft.AspNetCore.Authentication.Cookies;
 using Microsoft.IdentityModel.Tokens;

public class LoginModel : PageModel
{
    public async Task OnGet(string redirectUri)
    {
        await HttpContext.ChallengeAsync("oidc", new 
            AuthenticationProperties { RedirectUri = redirectUri } );
    }  
}

此代码对您在Startup类中定义的Open Id Connect身份验证方案提出了挑战.

This code starts the challenge for the Open Id Connect authentication scheme you defined in the Startup class.

  1. 创建一个注销剃刀"页面Logout.cshtml(Logout.cshtml.cs)并将它们也放置在Pages文件夹中:

  1. Create a Logout Razor page Logout.cshtml (Logout.cshtml.cs) and place them in the Pages folder as well:

using Microsoft.AspNetCore.Authentication;

public class LogoutModel : PageModel { public async Task<IActionResult> OnGetAsync() { await HttpContext.SignOutAsync(); return Redirect("/"); }}

public class LogoutModel : PageModel { public async Task<IActionResult> OnGetAsync() { await HttpContext.SignOutAsync(); return Redirect("/"); }}

此代码将您注销,将您重定向到Blazor应用程序的主页.

This code signs you out, redirecting you to the Home page of your Blazor app.

用以下代码替换App.razor中的代码:

Replace the code in App.razor with the following code:

@inject NavigationManager NavigationManager

<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
            <NotAuthorized>
                @{
                    var returnUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);

                    NavigationManager.NavigateTo($"login?redirectUri={returnUrl}", forceLoad: true);

                }

            </NotAuthorized>
            <Authorizing>
                Wait...
            </Authorizing>
        </AuthorizeRouteView>
    </Found>
    <NotFound>

        <LayoutView Layout="@typeof(MainLayout)">
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>

    </NotFound>

</Router>
</CascadingAuthenticationState>

使用以下代码替换Startup类中的代码:

Replace the code in the Startup class with the following:

using Microsoft.AspNetCore.Authentication.OpenIdConnect; 
using Microsoft.AspNetCore.Authorization; 
using Microsoft.AspNetCore.Mvc.Authorization; 
using System.Net.Http;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Logging;


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.AddRazorPages();
        services.AddServerSideBlazor();
        services.AddAuthorizationCore();
        services.AddSingleton<WeatherForecastService>();

        services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultAuthenticateScheme = 
                 CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultSignInScheme = 
                CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = 
               OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect("oidc", options =>
         {
             options.Authority = "https://demo.identityserver.io/";
             options.ClientId = "interactive.confidential.short"; 
             options.ClientSecret = "secret";
             options.ResponseType = "code";
             options.SaveTokens = true;
             options.GetClaimsFromUserInfoEndpoint = true;
             options.UseTokenLifetime = false;
             options.Scope.Add("openid");
             options.Scope.Add("profile");
             options.TokenValidationParameters = new 
                    TokenValidationParameters
                    {
                        NameClaimType = "name"
                    };

             options.Events = new OpenIdConnectEvents
             {
               OnAccessDenied = context =>
                        {
                          context.HandleResponse();
                          context.Response.Redirect("/");
                          return Task.CompletedTask;
                       }
       };
 });

}


  // 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();
        }
        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.UseStaticFiles();
        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();


        app.UseEndpoints(endpoints =>
        {
            endpoints.MapBlazorHub();
            endpoints.MapFallbackToPage("/_Host");
        });
    }
}

重要:在以上所有代码示例中,您都必须根据需要添加using语句.默认情况下,大多数都是提供的.此处提供的使用是启用身份验证和授权流程所必需的.

IMPORTANT: in all the code sample above you'll have to add using statements as necessary. Most of them are provided by default. The using provided here are those necessary to enable the authentication and authorization flow.

  • 运行您的应用程序,单击登录"按钮进行身份验证.您将被重定向到IdentityServer测试服务器,该服务器允许您执行OIDC登录.您可以输入用户名: bob 和密码 bob ,然后单击确定"按钮,您将被重定向到您的主页.另请注意,您可以使用外部登录提供商Google(尝试).请注意,使用身份服务器登录后,LoginDisplay组件将显示字符串"Hello,".
  • Run your app, click on the log in button to authenticate. You are being redirected to IdentityServer test server which allows you to perform an OIDC login. You may enter a user name: bob and password bob, and after click the OK button, you'll be redirected to your home page. Note also that you can use the external login provider Google (try it). Note that after you've logged in with identity server, the LoginDisplay component displays the string "Hello, ".

注意:在尝试应用程序时,如果要重定向到身份服务器的登录页面,则应清除浏览数据,否则,浏览器可能会使用缓存的数据.记住,这是基于cookie的授权机制...

Note: While you're experimenting with your app, you should clear the browsing data, if you want to be redirected to the identity server's login page, otherwise, your browser may use the cached data. Remember, this is a cookie-based authorization mechanism...

请注意,如此处所述创建登录机制并不能使您的应用程序比以前更安全.任何用户都无需登录即可访问您的Web资源.为了保护网站的某些部分,您还必须实施授权,通常,经过身份验证的用户有权访问受保护的资源,除非实施了其他措施,例如角色,策略等.以下是演示如何进行的.您可以防止未经授权的用户保护Fetchdata页面(同样,经过身份验证的用户被视为有权访问Fetchdata页面).

Note that creating a login mechanism as is done here does not make your app more secured than before. Any user can access your web resources without needing to log in at all. In order to secure parts of your web site, you have to implement authorization as well, conventionally, an authenticated user is authorized to access secured resource, unless other measures are implemented, such as roles, policies, etc. The following is a demonstration how you can secure your Fetchdata page from unauthorized users (again, authenticated user is considered authorized to access the Fetchdata page).

  1. 在Fetchdata组件页面的顶部,为Authorize属性添加@attribute指令,如下所示:@attribute [Authorize]当未经身份验证的用户尝试访问Fetchdata页面时,将执行AuthorizeRouteView.NotAuthorized委托属性,因此我们可以添加一些代码以将用户重定向到同一身份服务器的登录页面以进行身份​​验证.
  2. NotAuthorized元素中的代码如下:

  1. At the top of the Fetchdata component page add the @attribute directive for the Authorize attribute, like this: @attribute [Authorize]When an unauthenticated user tries to access the Fetchdata page, the AuthorizeRouteView.NotAuthorized delegate property is executed, so we can add some code to redirect the user to the same identity server's login page to authenticate.
  2. The code within the NotAuthorized element looks like this:

<NotAuthorized> @{ var returnUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); NavigationManager.NavigateTo($"login?redirectUri= {returnUrl}", forceLoad: true); }</NotAuthorized>

<NotAuthorized> @{ var returnUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); NavigationManager.NavigateTo($"login?redirectUri= {returnUrl}", forceLoad: true); }</NotAuthorized>

这将检索您尝试访问的最后一个页面的URL,即Fetchdata页面,然后导航到执行密码质询的Login Razor页面,即,将用户重定向到Identity Server的登录页面.进行身份验证.

This retrieves the url of the last page you were trying to access, the Fetchdata page, and then navigates to the Login Razor page from which a password challenge is performed, that is, the user is redirected to the identity server's login page to authenticate.

用户身份验证后,他将被重定向到Fetchdata页面.

After the user has authenticated he's redirected to the Fetchdata page.

祝你好运...

这篇关于如何通过IdentityServer4将OpenIdConnect添加到ASP.NET Core ServerSide Blazor Web应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-25 17:03