首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >服务器端Blazor中的OIDC认证

服务器端Blazor中的OIDC认证
EN

Stack Overflow用户
提问于 2020-11-16 06:37:53
回答 2查看 5.4K关注 0票数 3

我使用了这个方法,但不知怎么的,它是不正确的,因为@attribute [AllowAnonymous]没有真正起作用,所以我使用[Authorized]属性而不是[AllowAnonymous],然后删除RequireAuthenticatedUser,但是OIDC不会将客户端重定向到服务器登录页面。

我在blazor中检查了SteveSanderson github文章的身份验证和授权,但他没有谈到OIDC。

那我该怎么处理呢?

启动课程:

代码语言:javascript
复制
services.AddAuthentication(config =>
{
    config.DefaultScheme = "Cookie";
    config.DefaultChallengeScheme = "oidc";
})
    .AddCookie("Cookie")
    .AddOpenIdConnect("oidc", config =>
    {
        config.Authority = "https://localhost:44313/";
        config.ClientId = "client";
        config.ClientSecret = "secret";
        config.SaveTokens = true;
        config.ResponseType = "code";
        config.SignedOutCallbackPath = "/";
        config.Scope.Add("openid");
        config.Scope.Add("api1");
        config.Scope.Add("offline_access");
    });

services.AddMvcCore(options =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser() // site-wide auth
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
});
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-11-16 12:17:50

以下是这个问题的完整和可行的解决办法:

首先,您需要提供一个身份验证挑战请求机制,该机制允许重定向到身份验证代理(如IdentityServer )。这只有在HttpContext中才能实现,SignalR (Blazor )中没有这种功能。为了解决这个问题,我们将添加几个HttpContext可用的Razor页面。答案更多..。

创建一个Blazor服务器应用程序。

安装-Package Microsoft.AspNetCore.Authentication.OpenIdConnect -Version 3.1.0或更高版本。

创建一个名为LoginDisplay (LoginDisplay.razor)的组件,并将其放在共享文件夹中。此组件用于MainLayout组件中:

代码语言:javascript
复制
<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锚元素之上,如下所示

代码语言:javascript
复制
<div class="top-row px-4">
    <LoginDisplay />
    <a href="https://learn.microsoft.com/aspnet/" target="_blank">About</a>
</div>

注意:为了将登录请求和注销请求重定向到IdentityServer,我们必须创建两个Razor页面,如下所示:

  1. 创建Login页面Login.cshtml ( Login.cshtml.cs ),并将它们放在Pages文件夹中,如下所示:Login.cshtml.cs
代码语言:javascript
复制
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身份验证方案的挑战。

  1. 创建一个Logout页面Logout.cshtml ( Logout.cshtml.cs ),并将它们放在Pages文件夹中:Logout.cshtml.cs
代码语言:javascript
复制
using Microsoft.AspNetCore.Authentication;

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

这段代码指示你退出,将你重定向到你的Blazor应用程序的主页。

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

代码语言:javascript
复制
@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类中的代码替换为以下代码:

代码语言:javascript
复制
using Microsoft.AspNetCore.Authentication.OpenIdConnect; 
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

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");
        });
    }
}

重要:在上面的所有代码示例中,您必须根据需要添加使用语句。其中大多数都是默认提供的。这里提供的使用是启用身份验证和授权流所必需的。

  • 运行您的应用程序,单击登录按钮进行身份验证。您将被重定向到IdentityServer测试服务器,该服务器允许您执行OIDC登录。您可以输入用户名: bob和密码bob,单击OK按钮后,您将被重定向到您的主页。还请注意,您可以使用外部登录提供程序Google (尝试一下)。注意,在您使用identity服务器登录之后,LoginDisplay组件将显示字符串"Hello, <your user name>"

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

请注意,像这里这样创建登录机制并不能使您的应用程序比以前更加安全。任何用户都可以访问您的web资源,而不需要登录。为了保护网站的部分安全,您还必须实现授权,通常,通过身份验证的用户有权访问安全资源,除非实现了其他措施,如角色、策略等。下面是如何从未经授权的用户保护Fetchdata页面的演示(同样,经过身份验证的用户被认为有权访问Fetchdata页面)。

在Fetchdata组件页面的顶部为Authorize属性添加Authorize指令,如:当未经身份验证的用户试图访问Fetchdata页面时,执行AuthorizeRouteView.NotAuthorized委托属性,因此我们可以添加一些代码将用户重定向到同一个身份服务器的登录页以进行身份验证。

NotAuthorized元素中的代码如下所示:

代码语言:javascript
复制
<NotAuthorized>
    @{
        var returnUrl = 
        NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
        NavigationManager.NavigateTo($"login?redirectUri= 
                              {returnUrl}", forceLoad: true);
     }
</NotAuthorized>

这将检索您试图访问的上一页的url、FetchData页,然后导航到执行密码挑战的Login页面,即用户被重定向到身份服务器的登录页以进行身份验证。

用户通过身份验证后,它们将被重定向到FetchData页面。

票数 12
EN

Stack Overflow用户

发布于 2020-11-16 08:57:22

对于服务器端Blazor,身份验证发生在承载Blazor应用程序的Razor页面上。对于默认模板,这是_Host.cshtml Razor页面,它被配置为服务器端路由的后备页面。因为页面类似于普通的Razor页面,所以您可以在那里使用[Authorize][AllowAnonymous]属性。

应用于_Host.cshtml的任何授权都会影响对Blazor应用程序本身的一般访问权限。如果只希望通过身份验证的用户访问应用程序,则需要授权;如果希望任何未经身份验证的用户访问应用程序,则不能保护应用程序访问本身。

该页面的授权并不意味着您不能在应用程序中获得更细粒度的授权。您仍然可以对应用程序中的特定组件使用不同的规则和策略。为此,您可以使用<AuthorizeView>组件。

对于服务器端Blazor来说,有两种常见的场景:

  • 对整个Blazor应用程序的访问仅限于经过身份验证的用户。未经身份验证的用户应该立即进行身份验证(例如使用OIDC),这样就不会有匿名用户访问该应用程序。 在这种情况下,应该通过通过_Host.cshtml属性或在AddRazorPages()调用中使用约定来要求经过身份验证的用户来保护AddRazorPages()。 在不经过身份验证的情况下访问Blazor应用程序时,默认的授权中间件将导致身份验证挑战,并重定向到OIDC登录。
  • 未经身份验证的用户应该能够访问Blazor应用程序,但是Blazor应用程序将使用<AuthorizeView>IAuthorizationService进行更详细的授权。 在这种情况下,不能保护_Host.cshtml,因为匿名用户需要访问它。这也意味着作为Razor页面一部分运行的默认授权中间件不会做任何事情。所以你必须自己来应对挑战。 要做到这一点,“简单”的方法是提供一个登录链接到另一个服务器端路由,然后触发身份验证挑战并重定向到OIDC登录。例如,您可以使用这样的MVC操作: HttpGet("/login")公共IActionResult登录() =>挑战(); 在您的Blazor应用程序中,您现在可以添加到此路由的链接,并允许用户以这种方式签名: 注册为@context.User.Identity.Name。在这里签到
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64853618

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档