Blazor Service 身份验证

写在

Blazor 是微软的新型的web开发方案,用来做全栈开发真是太爽了。

之前用 Blazor 做了几个小应用,但是一直没有去做身份验证系统,之前也没有ASP.NET的基础,C#也是最近学的,而且重要的是,网上居然几乎没有相关的资料,于是咱就结合网上的一些信息和微软的官方文档(微软的文档是我见过最好的文档了)做了一个身份鉴权的小Demo。

首先创建 Blazor Service 项目:

然后在项目的目录下创建Auth目录存放鉴权的基础设施

Provider 是鉴权的服务提供者

UserAccount 是用户账号模型

UserAccountService 是用户账号服务

UserSession 是用户 session 数据模型

在 Provider 下写自定义的基础认证服务,这里使用的session的形式做鉴权认证。

using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
using System.Security.Claims;

namespace BSAuth.Auth
{
    public class Provider : AuthenticationStateProvider
    {
        private readonly ProtectedSessionStorage _sessionStorage;
        private readonly ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity());
        public Provider(ProtectedSessionStorage sessionStorage)
        {
            _sessionStorage = sessionStorage;
        }

        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            try
            {
                var userSessionStorageResult = await _sessionStorage.GetAsync<UserSession>("UserSession");
                var userSession = userSessionStorageResult.Success ? userSessionStorageResult.Value : null;
                if (userSession == null)
                {
                    return await Task.FromResult(new AuthenticationState(_anonymous));
                }
                var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
                {
                    new Claim(ClaimTypes.Name,userSession.UserName),
                    new Claim(ClaimTypes.Role,userSession.Role)
                }, "customAuth")); ;
                return await Task.FromResult(new AuthenticationState(claimsPrincipal));
            }
            catch
            {
                return await Task.FromResult(new AuthenticationState(_anonymous));
            }

        }
        public async Task UpdateAuthState(UserSession userSession)
        {
            ClaimsPrincipal claimsPrincipal;
            if (userSession is not null)
            {
                await _sessionStorage.SetAsync("UserSession", userSession);
                claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
                {
                    new Claim(ClaimTypes.Name,userSession.UserName),
                    new Claim(ClaimTypes.Role,userSession.Role)
                }));
            }
            else
            {
                await _sessionStorage.DeleteAsync("UserSession");
                claimsPrincipal = _anonymous;
            }
            NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(claimsPrincipal)));
        }
    }
}

创建 UserSession 模型和 UserAccount 模型

namespace BSAuth.Auth
{
    public class UserSession
    {
        public string UserName { get; set;}
        public string Role { get; set;}
    }
}
namespace BSAuth.Auth
{
    public class UserAccount
    {
        public string UserName { get; set; }
        public string Password { get; set; }
        public string Role { get; set; }
    }
}

然后建立账户系统服务,这里Demo用的内存数据模拟,实际应该使用数据库

namespace BSAuth.Auth
{
    public class UserAccountService
    {
        private List<UserAccount> _user;
        public UserAccountService()
        {
            _user = new List<UserAccount>
            {
                new UserAccount{UserName="张三",Password="zs",Role="admin"},
                new UserAccount{UserName="李四",Password="ls",Role="user"}
            };
        }
        public UserAccount? GetByUserName(string userName)
        {
            return _user.FirstOrDefault(x => x.UserName == userName);
        }
    }
}

然后鉴权服务就做好啦,下面要将这些服务注入到项目中。

在Program里依赖注入的形式注入基础认证服务和账号服务

接下来在App.razor下使用认证视图标签

一个简单的登录页面示例;

@page "/login"
@inject IJSRuntime ij
@using BSAuth.Auth
@inject UserAccountService userAccountService
@inject AuthenticationStateProvider authStateProvider
@inject NavigationManager navigation
<h3>Login</h3>
<input @bind="UserName" type="text"/>
<input @bind="PassWord" type="password"/>
<button @onclick="LoginAuth">登录</button>
@code {
    string UserName { get; set; }
    string PassWord{ get; set; }
    private async Task LoginAuth()
    { 
        var userAccount = userAccountService.GetByUserName(UserName);
        if(userAccount is  null || userAccount.Password != PassWord)
        {
            await ij.InvokeVoidAsync("alert", "登录失败");
            return;
        }
        var provider = (Provider)authStateProvider;
        await provider.UpdateAuthState(new UserSession
            {
                UserName = userAccount.UserName,
                Role = userAccount.Role
            });
        await ij.InvokeVoidAsync("alert", "登录成功");
        navigation.NavigateTo("/");
    }
}

然后可以在需要鉴权的视图资源下使用 AuthorizeView 组件

具体使用方式请参照微软文档:ASP.NET Core Blazor 身份验证和授权 | Microsoft Learn


评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注