服务器Blazor应用程序简介
Blazor是微软推出的一项令人兴奋的新技术,它将允许开发人员将C#带到客户端。服务器和客户端组件是用相同的语言编写的,可以互换使用和重用。Blazor有两种风格,即服务器和客户端应用程序。在本教程中,您将使用服务器Blazor应用程序,其中C#代码在服务器上运行,并使用SignalR 。
我将向您展示如何将Okta与服务器端的Blazor应用程序集成。然后你将学习如何使用Okta的多因素认证系统来提供一个额外的安全层。多因素认证(MFA)是一种技术,在这种技术中,用户必须出示两个或两个以上的凭证,才能成功获得访问权,完成登录或其他交易。 有许多方法可以做到这一点。 最常见的是在用户被认证后,通过电子邮件或短信向用户发送一个代码。 然后,用户可以验证该代码,从而确定该用户知道适当的凭证,但也可以访问记录中的电话号码或电子邮件地址。
你需要的东西
- 你最喜欢的IDE(我将使用Visual Studio 2019,但Visual Studio Code是另一个不错的选择。)
- 一个git资源库
- .NET5
- 一个Okta开发者账户
- Okta CLI工具
创建您的Okta应用程序
使用Okta CLI,为.NET Blazor创建一个新的Okta应用程序。或者,使用您的Okta管理门户来完成这项工作。导航到应用程序,点击Create App Integration ,为Sign in Type 选择OIDC,为Application Type 选择Web,并为您的本地主机环境填写具体内容。
在你开始之前,你需要一个免费的Okta开发者账户。安装Okta CLI并运行okta register 来注册一个新的账户。如果你已经有一个账户,运行okta login 。然后,运行okta apps create 。选择默认的应用程序名称,或根据你的需要进行更改。 选择Web,然后按回车键。
选择ASP.NET Core。 然后,将重定向URI改为https://localhost:44378/authorization-code/callback ,并使用https://localhost:44378/signout/callback ,作为注销重定向URI。
Okta CLI是做什么的?
Okta CLI将在您的Okta机构中创建一个OIDC网络应用。它将添加您指定的重定向URI,并授予Everyone组的访问权限。当它完成后,您会看到如下输出:
Okta application configuration has been written to: /path/to/app/.okta.env
运行cat .okta.env (或Windows上的type .okta.env ),查看你的应用程序的发行者和凭证:
export OKTA_OAUTH2_ISSUER="https://dev-133337.okta.com/oauth2/default"
export OKTA_OAUTH2_CLIENT_ID="0oab8eb55Kb9jdMIr5d6"
export OKTA_OAUTH2_CLIENT_SECRET="NEVER-SHOW-SECRETS"
您的Okta域是发行者的第一部分,在/oauth2/default 。
注意:你也可以使用Okta管理控制台来创建你的应用程序。更多信息请参见创建一个ASP.NET Core应用程序。
一旦您完成了Okta应用程序的设置,您将需要启用多因素认证,然后在您的应用程序上启用它。现在,导航到管理门户,在应用程序下选择您刚刚创建的应用程序。点击 "登录",在 "登录策略"部分点击 "添加规则"。
在 "访问"部分,点击 "多因素设置"。对于这个应用,您将只启用短信验证,但您可以在这个页面看到Okta允许的因素类型。在SMS认证标签下,将下拉菜单设置为激活。
返回到规则页面,点击提示因素,然后点击每次登录。给您的新规则起个名字,然后点击保存。该登录策略现在将对任何试图登录该应用程序的人进行触发。
创建你的Blazor应用程序
打开Visual Studio 2019,选择创建一个新项目。在创建项目页面上找到Blazor应用程序条目。 请注意,如果您使用的是不同版本的Visual Studio,您的项目创建模板可能看起来有所不同。
在创建一个新的Blazor应用部分,选择Blazor服务器应用,并给它一分钟时间进行设置。
一旦完成,您将看到配置您的新项目屏幕。 将您的项目命名为Okta_ServerDemo,然后按创建。
设置完成后,花一分钟时间运行该应用程序,看看Blazor是如何设置的。对于本教程来说,Blazor设置中附带的演示应用程序就足够了。不过我们需要对该应用程序做一些修改。
设置您的应用程序
首先,通过命令行或NuGet包管理器从NuGet安装Okta.AspNetCore 包。这将使与Okta的集成变得快速而简单:
Install-Package Okta.AspNetCore -Version 4.0.0
接下来,打开appsettings.Development.json ,用下面的内容编辑代码:
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Okta": {
"Domain": "{yourOktaDomain}",
"ClientId": "{yourClientId}}",
"ClientSecret": "{yourClientSecret}"
}
}
如果你不知道在哪里可以找到Okta的设置值,你应该可以在.okta.env 。你也可以从Okta管理控制台检索到它们。
现在你可以改变你的Startup.cs ,用Okta配置认证:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Okta_ServerDemo.Data;
using System;
using System.Collections.Generic;
using Okta.AspNetCore;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
namespace Okta_ServerDemo
{
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.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOktaMvc(new OktaMvcOptions
{
OktaDomain = Configuration.GetValue<string>("Okta:Domain"),
ClientId = Configuration.GetValue<string>("Okta:ClientId"),
ClientSecret = Configuration.GetValue<string>("Okta:ClientSecret"),
Scope = new List<string> { "openid", "profile", "email" },
});
}
// 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");
});
}
}
}
编写你的应用程序
接下来,你可以把注意力转移到页面上。首先,你要用以下代码编辑App.razor:
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<Authorizing>
<p>Determining session state, please wait...</p>
</Authorizing>
<NotAuthorized>
<h1>Sorry</h1>
<p>You're not authorized to reach this page. You need to log in.</p>
<UserComponent></UserComponent>
</NotAuthorized>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
这个页面的大部分内容是设置过程中的模板。但你需要做几个重要的改动。首先,将整个代码包裹在CascadingAuthenticationState 元素中。这将把认证状态级联到你的每个路由。接下来,你需要将RouteView 改为AuthorizeView ,并处理Authorizing 和NotAuthorized 的状态。
在这一点上,你可能已经注意到,UserComponent.razor 并不存在,所以现在在Shared 文件夹中创建它。在其中添加以下代码:
<AuthorizeView>
<Authorized>
<a href="logout">Log out</a>
</Authorized>
<NotAuthorized>
<a href="login?redirectUri=/">Log in</a>
</NotAuthorized>
</AuthorizeView>
这个组件利用了上面的CascadingAuthenticationState ,并展示了两个不同的视图。如果用户已经登录,那么你就显示一个注销按钮。如果用户是未授权的,则向他们展示一个登录按钮。
这里的两个路由,login 和logout ,接下来需要实现。在页面下,添加一个新的RazorPage ,名为Login 。Razor页面的创建有两个组件,一个是cshtml 文件,一个是.cs 文件。由于你的登录页面是由Okta托管的,你不需要在.cshtml 文件中进行任何展示。然而,你仍然需要告诉页面使用哪个模型文件。打开Login.cshtml ,添加以下代码:
@page
@model Okta_ServerDemo.Pages.LoginModel
@{
}
接下来,打开Login.cshtml.cs ,添加登录逻辑:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Authentication;
using Okta.AspNetCore;
namespace Okta_ServerDemo.Pages
{
public class LoginModel : PageModel
{
public async Task OnGet(string redirectUri)
{
await HttpContext.ChallengeAsync(OktaDefaults.MvcAuthenticationScheme, new AuthenticationProperties
{
RedirectUri = redirectUri
});
}
}
}
如果你在任何ASP.NET应用程序中使用过Okta,这段代码应该看起来很熟悉。你只是返回Okta提供的Challenge 。这将把用户重定向到Okta的登录页面。
在你认证之后,你会被要求提供你的电话号码,或者被提示向你的手机发送一个代码。这取决于您是否已经在Okta中设置了您的手机。如果您没有,请将您的电话号码添加到您的账户中并验证代码;否则,请点击发送代码,然后在此页面验证代码。就这样,您的应用程序现在可以使用Okta的MFA来保证安全了你可以选择Okta网站上的几种MFA方法,从电子邮件和电话代码到物理验证器。
现在你可以像添加Login 页面一样添加Logout 页面。同样,由于这里没有演示,你的.cshtml 文件将声明模型页面,没有任何HTML:
@page
@model Okta_ServerDemo.Pages.LogoutModel
@{
}
你的Logout.cshtml.cs 文件将包含库存的ASP.Net Core注销逻辑:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Okta.AspNetCore;
namespace Okta_ServerDemo.Pages
{
public class LogoutModel : PageModel
{
public SignOutResult OnGet()
{
return new SignOutResult(
new[]
{
OktaDefaults.MvcAuthenticationScheme,
CookieAuthenticationDefaults.AuthenticationScheme,
},
new AuthenticationProperties { RedirectUri = "/" });
}
}
}
最后,Counter 和FetchData 页面将需要用户认证。
打开Counter.razor ,添加@attribute [Authorize] 注释:
@page "/counter"
@attribute [Authorize]
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
这段代码几乎与模板代码相同,除了页面顶部的Authorize 属性。像ASP.Net Core一样,这个属性将要求用户在访问它之前登录。
同样地,用下面的代码编辑FetchData.razor 文件:
@page "/fetchdata"
@using Okta_ServerDemo.Data
@inject WeatherForecastService ForecastService
@attribute [Authorize]
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
}
}
同样,这里唯一的变化是增加了Authorize 属性。
测试你的应用程序
现在启动应用程序并导航到Counter 页面。
你会看到在你的App.razor 页面上发现的信息。点击登录按钮,走完认证和MFA过程。一旦你登录了,你应该看到`**页面。
就是这样!如果你想看一下这个解决方案的全部内容,请查看GitHub repo。
了解更多关于与Blazor合作的信息
有了Okta,用MFA保护您的应用程序比以往任何时候都要容易。只需改变一些配置,Okta就能完成繁重的工作,为您的Blazor服务器端应用增加一层安全保障。