如何在服务器端Blazor中实现认证和授权

1,193 阅读6分钟

在服务器端Blazor中实施认证和授权

今天,有许多网站提供重要的服务。为了开展这项工作,他们需要保护他们的网站不受不道德用户的影响。这就导致了在他们的网站上引入认证和授权。

认证是验证用户或进程的身份的过程或行动。每个设备的用户认证确保公司识别使用该设备的个人,而授权给予用户访问服务的权限。

在本教程中,我们将讨论认证和授权是如何在功能层中实现的。

有三个不同的基本层。

  • 用户界面(UI)层
  • 功能层
  • 对象关系映射/数据库

先决条件

要完成本教程,我们需要。

  • 安装[Visual Studio]。
  • 对[C#]的基本了解
  • 对[Blazor]的基本了解

开始学习

我们将首先创建一个服务器端的Blazor应用程序。为此,我们将打开Microsoft Visual Studio并选择Create a New Project

New Project

在下一个屏幕上,我们将选择Blazor server App ,然后点击Next

Type of Application

在下一个屏幕上,我们需要配置我们的新项目,我们将输入项目的名称并点击Next

Name of Application

在下一个屏幕上,我们将选择.NET Core 3.1 (Long-term support) 作为我们的目标框架,然后点击Create

Target framework

用户界面

这是用户与之互动的一层。它使用户能够注册、登录、恢复密码和管理用户资料。

功能层

这一层是用来验证和授权用户信息的。在我们的项目中,我们将在这一层工作,实现授权功能。

为了开始我们的认证功能,我们将进入startup.cs 文件,在configure 方法中,在else语句后添加以下代码,以启用认证和授权。

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

在下一步,我们将添加一个认证状态提供者,它将为我们提供用户的状态。要做到这一点,我们将在我们的数据文件夹中添加一个名为AuthStateProvider 的类。

现在在创建的类中,为了返回硬编码用户的认证状态,例如,johndoe@gmail.com ,因为没有用户登录到系统中,我们将使用下面的代码。

namespace ServerApp.Data
{
    public class NewAuthenticationStateProvider : AuthenticationStateProvider
    {
        public override Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            var identity = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.Name, "Johndoe@gmail.com"),
            }, "apiauth_ype");
            var user = new ClaimsPrincipal(identity);

            return Task.FromResult(new AuthenticationState(user));
        }
    }
}

下一件事是在startup.cs 文件中添加认证状态提供者。这是在ConfigureServices 方法中完成的。

使用下面的代码行。

services.AddScoped<NewAuthenticationStateProvider, NewAuthenticationStateProvider>();

在上面的代码中,我们正在添加一个范围内的状态提供者的实例,并用NewAuthenticationStateProvider 。现在我们告诉应用程序路由,我们期待NewAuthenticationStateProvider ,作为级联参数,可以在整个应用程序中传递,我们可以使用它。

为了实现这一点,进入app.razor 文件,编辑这行代码<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /><AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />AuthorizeRouteView 将状态提供者作为级联参数,可以在需要时使用。

我们将再次在<CascadingAuthenticationState> 中添加Not found 参数内的代码。这是两个将认证状态作为级联的状态。即

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

现在,在索引页上,我们需要在屏幕上显示认证用户的名字,如下所示。

<SurveyPrompt Title="How is Blazor working for you?" />
<AuthorizeView>
    <Authorized>
        <p>Hello @context.User.Identity.Name</p>
    </Authorized>
    <NotAuthorized>
        <p>Please log in to access the page. Thank you</p>
    </NotAuthorized>
</AuthorizeView>

@context.User.Identity.Name 是在用户成功登录时显示用户的名字。如果用户没有登录,他们将看到 。Please log in to access the page. Thank you

接下来,我们需要创建一个登录页面,使用户能够登录。要做到这一点,请到pages文件夹中,添加另一个页面。

打开该文件并添加以下代码。

@page "/login"
@Using ServerApp.Data
@code  {
private User user;
protected ovveride Task OnInitializedAsync()
{
   user = new User();
   return base.OnInitializedAsync();
}
private async Task<bool> Validate User()
    {
    return await Task.FromResult(true);
    }
}

现在,我们需要在用户被验证时改变状态,为了做到这一点,我们将在NewAuthenticationStateProvider 文件中创建一个函数,该函数接受一个字符串作为参数,并调用它UserAuthenticated ,然后将其发送到NotifyAuthenticationStateChanged 。这将告诉认证状态提供者,状态已经改变。

 public void UserAuthenticated(string name)
        {
            var identity = new ClaimsIdentity(new[]
          {
                new Claim(ClaimTypes.Name, "johndoe@gmail.com"),
            }, "apiauth_ype");
            var user = new ClaimsPrincipal(identity);
            NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
        }

在login razor页面中,我们将使用下面的代码行注入AuthenticationStateProvider

@inject AuthenticationStateProvider AuthenticationStateProvider

当用户点击登录时,他们需要被标记为已认证,这是通过传入用户的电子邮件地址来完成的,如下面的代码。

((NewAuthenticationStateProvider)AuthenticationStateProvider).UserAuthenticated(user.EmailAddress);

用户现在需要从登录界面导航到索引页,所以你将在login.razor page ,即注入一个导航管理器。

@inject NavigationManger NavigationManager;

为了导航到主页,我们将使用下面这行代码。

NavigationManager.NavigateTo("/");

当我们刷新我们的浏览器时,我们注意到我们被签出了。为了确保我们没有被签出,我们将下载一个名为Blazored.SessionStorageNUGET 包,并将其添加到startup.cs 文件中。

services.AddBlazoredSessionStorage();

现在在登录页面,我们需要注入会话存储,如下图所示。

@inject Blazored.SessionStorage.ISessionStorageService sessionStorage

我们还将添加一个密钥,这个密钥将是用户的电子邮件地址,这样即使用户刷新浏览器,用户名也会被保存在会话存储中。要做到这一点,请在private async Task<bool> Validate User() 函数中添加以下代码。

await sessionStorage.setItemAsync("emailAddress", user.emailAdress);

现在,为了使用会话存储,在NewAuthenticationStateProvider 中写一个构造函数。

private ISessionStorageService _sessionStorageService;
public NewAuthenticationStateProvider(ISessionStorageService sessionStorageService)
{
     _sessionStorageService = SessionStorageService;
}

现在我们有了会话状态提供者,当浏览器被刷新并且用户有一些值时,我们需要浏览器返回用户数据,否则就注销用户。这可以通过在public override Task<AuthenticationState> GetAuthenticationStateAsync() 函数中使用下面的代码来实现,并在每次刷新浏览器时调用它。

var emailAddress = await _sessionStorageService.GetItemAsync<string>(emailAddress);
ClaimsIdentity identity;
if(emailAddress != null)
{
     identity = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.Name, "emailAddress"),
            }, "apiauth_ype");
}
else
{
     identity = new ClaimsIdentity();
}

我们还需要告诉该函数它是一个异步函数,因为我们在上面的代码中使用了await 关键字。

public override async Task<AuthenticationState> GetAuthenticationStateAsync()

通过添加await 关键字,将代码中的return Task.FromResult(true); 行改为return await Task.FromResult(true); 。最后要做的是实现注销功能。我们将导航到shared 文件夹,打开MainLayout.razor 文件,然后在div class ="main" 里面创建一个授权视图,即。

<AuthorizeView>
    <Authorized>
        <a href = "/login>" @onclick = "(() =>Logout())>Logout</a>
    </Authorized>
    <NotAuthorized>
        <a href = "/login>">Login</a>
    </NotAuthorized>
</AuthorizeView>

上面的代码基本上是告诉用户,如果他们没有登录,就要登录,如果他们已经登录了,就要注销。

我们将通过在NewAuthenticationStateProvider 中创建一个方法来实现注销功能,将用户标记为注销。即

public UserLoggedOut()
{
            _sessionStorageService.RemoveItemAsync("emailAddresss");
            var identity = new ClaimsIdentity();
            var user = new ClaimsPrincipal(identity);
            NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
}

我们将需要在MainLayout.razor 页面中注入授权状态提供者。

@inject AuthenticationStateProvider AuthenticationStateProvider

@code 部分添加下面的代码,标记用户为注销。

public void Logout()
{
     ((NewAuthenticaticationStateProvider)AuthenticationStateProvider).UserLoggedOut();
}

对象关系映射或数据库

该层存储、操作和更新用户信息。

总结

从这个教程中,我们了解到如何在blazor中实现服务器端授权,通过带你完成每一个步骤,易于理解和跟随。

注意项目中的任何错误都是通过导入必要的C#包来解决的。