Blazor入门100天 : 身份验证和授权 (2) - 角色/组件/特性/过程逻辑

发布时间 2023-03-22 19:10:44作者: AlexChow

目录

  1. 建立默认带身份验证 Blazor 程序
  2. `角色/组件/特性/过程逻辑
  3. DB 改 Sqlite
  4. 将自定义字段添加到用户表
  5. 脚手架拉取IDS文件,本地化资源
  6. freesql 生成实体类,freesql 管理ids数据表
  7. 初始化 Roles,freesql 外键 => 导航属性
  8. 完善 freesql 和 bb 特性

本节源码

https://github.com/densen2014/Blazor100/tree/Blazor-教程15-2/b15blazorIDS

更改默认密码策略,添加管理员角色

有些同学说一直使用1qaz@WSX密码感觉不爽,那我们改一下策略

编辑Program.cs文件

找到

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

改为以下配置

builder.Services.AddDefaultIdentity<IdentityUser>(o =>
 {   // Password settings.
     o.Password.RequireDigit = false;
     o.Password.RequireLowercase = false;
     o.Password.RequireNonAlphanumeric = false;
     o.Password.RequireUppercase = false;
     o.Password.RequiredLength = 1;
     o.Password.RequiredUniqueChars = 1;
 }
)
.AddRoles<IdentityRole>()

编辑页面Index.razor

页面头部加入

@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Identity
@using System.Diagnostics.CodeAnalysis

初始化角色,添加默认管理员

最终页面代码

@code
{
    [Inject]
    [NotNull]
    protected UserManager<IdentityUser>? UserManager { get; set; }

    [Inject]
    [NotNull]
    protected RoleManager<IdentityRole>? RoleManager { get; set; }


    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        if (!firstRender) return;

        var RoleResult = await RoleManager.FindByNameAsync(AuthorizeRoles.Admin.ToString());
        if (RoleResult == null)
        {
            await RoleManager.CreateAsync(new IdentityRole(AuthorizeRoles.Admin.ToString()));
            Console.WriteLine("Admin Role Created");
        }

        var user = await UserManager.FindByNameAsync("test@app.com");
        if (user != null)
        {
            var UserResult = await UserManager.IsInRoleAsync(user, AuthorizeRoles.Admin.ToString());
            if (!UserResult)
            {
                await UserManager.AddToRoleAsync(user, AuthorizeRoles.Admin.ToString());
                Console.WriteLine("Admin Role Added to test@app.com");
            }
        }

        var chekRole = RoleManager.RoleExistsAsync(AuthorizeRoles.R110.ToString());
        if (chekRole.Result == false)
        {
            await RoleManager.CreateAsync(new IdentityRole(AuthorizeRoles.R110.ToString()));
            Console.WriteLine("R110Role Created");
        }

        chekRole = RoleManager.RoleExistsAsync(AuthorizeRoles.Superuser.ToString());
        if (chekRole.Result == false)
        {
            await RoleManager.CreateAsync(new IdentityRole(AuthorizeRoles.Superuser.ToString()));
            Console.WriteLine("Superuser Role Created");

        }

    }


    public enum AuthorizeRoles
    {
        Admin,
        Superuser,
        R110,
        R120,
        R130,
        R140,
    }

} 

参考第一篇重新注册账号, 点击 Register 注册账号

Email Password Confirm Password
test@app.com 000000 000000

登录后,刷新两次首页,test@app.com就会被代码设置为管理员组

<AuthorizeView>组件

编辑 Index.razor 文件,加入以下代码

<AuthorizeView>
    <Authorized>
        
        你好, @context.User.Identity?.Name

        @if (@context.User.IsInRole(AuthorizeRoles.Administrators.ToString()))
        {
            <span>管理员</span>
        }
        else if (@context.User.IsInRole(AuthorizeRoles.Superuser.ToString()))
        {
            <span>超级用户</span>
        }
        else
        {
            <span>能力者</span>
        }
    </Authorized>
    <NotAuthorized>
        <span>看起来你还没登录</span>
    </NotAuthorized>

</AuthorizeView> 

@code{
    public enum AuthorizeRoles
    {
        Superuser,
        Administrators,
        R110,
        R120,
        R130,
        R140,
    }

}

运行截图

检查登录信息

新建Razor组件: LogInfo

编辑页面

@page "/logInfo"

<PageTitle>登录信息</PageTitle>

<h1>登录信息</h1>

<button @onclick="LogUsername">检查登录信息</button>

<p>@authMessage</p>

@code 
{
    /// <summary>
    /// 级联参数获取身份验证状态数据
    /// </summary>
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private string authMessage;

    private async Task LogUsername()
    {
        var authState = await authenticationStateTask;
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

运行

添加导航菜单

编辑文件 Shared\NavMenu.razor

        <div class="nav-item px-3">
            <NavLink class="nav-link" href="logInfo">
                <span class="oi oi-plus" aria-hidden="true"></span> 登录信息
            </NavLink>
        </div>

注销按钮

编辑 Index.razor 文件,加入以下代码

@using Microsoft.AspNetCore.Components.Authorization 

        <form method="post" action="Identity/Account/Logout">
            <button type="submit" class="nav-link btn btn-link">Log out</button>
        </form>

基于策略的授权 / 基于角色或基于策略的授权

基于策略的授权需要Program.cs添加相关配置,这里带过就好,不展开讨论.

<p>基于角色或基于策略的授权 </p>

<AuthorizeView Roles="Admin, Superuser">
    <p>You can only see this if you're an Admin or Superuser.</p>
</AuthorizeView>

<p>基于策略的授权</p>

<AuthorizeView Policy="ContentEditor">
    <p>You can only see this if you satisfy the "ContentEditor" policy.</p>
</AuthorizeView>

在 Razor 组件中使用 [Authorize] 特性

新建AuthorizePage.razor组件

@page "/AuthorizePage"
@attribute [Authorize]

<PageTitle>已登录</PageTitle>

<h1>You can only see this if you're signed in.</h1> 

导航菜单Shared\NavMenu.razor

        <div class="nav-item px-3">
            <NavLink class="nav-link" href="AuthorizePage">
                <span class="oi oi-plus" aria-hidden="true"></span> 验证组件
            </NavLink>
        </div>

未登录状态

登录后状态

在 Razor 组件中使用 [Authorize(Roles = "Admin, Superuser")] 特性

新建AuthorizeAdminPage.razor组件

@page "/AuthorizeAdminPage"
@attribute [Authorize(Roles = "Admin, Superuser")]

<PageTitle>Admin 已登录</PageTitle>

<p>You can only see this if you're in the 'Admin' or 'Superuser' role.</p>

导航菜单Shared\NavMenu.razor

        <div class="nav-item px-3">
            <NavLink class="nav-link" href="AuthorizeAdminPage">
                <span class="oi oi-plus" aria-hidden="true"></span> Admin验证组件
            </NavLink>
        </div>

管理员账号test@app.com登录

普通账号test@test.com登录

过程逻辑中检查授权规则 AuthenticationState

新建AuthenticationStatePage.razor组件

@page "/AuthenticationStatePage"
@attribute [Authorize]

<PageTitle>Admin 已登录</PageTitle>

<pre>如果需要应用在过程逻辑中检查授权规则,请使用类型为 Task&lt;AuthenticationState&gt; 的级联参数来获取用户的 ClaimsPrincipal。 Task&lt;AuthenticationState&gt; 可以与其他服务(如 IAuthorizationService)结合使用来评估策略。</pre>

@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<button @onclick="@DoSomething">Do something important</button>


<p>@Msg</p>


@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private string? Msg { get; set; }

    private async Task DoSomething()
    {
        var user = (await authenticationStateTask).User;

        if (user.Identity.IsAuthenticated)
        {
            Msg = "Perform an action only available to authenticated (signed-in) users.";
        }

        if (user.IsInRole("admin"))
        {
            Msg = "Perform an action only available to users in the 'admin' role.";
        }

        //if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
        //    .Succeeded)
        //{
        //    Msg = "Perform an action only available to users satisfying the 'content-editor' policy.";
        //}
    }
}

导航菜单Shared\NavMenu.razor

        <div class="nav-item px-3">
            <NavLink class="nav-link" href="AuthenticationStatePage">
                <span class="oi oi-plus" aria-hidden="true"></span> 验证过程逻辑
            </NavLink>
        </div>

本节源码

https://github.com/densen2014/Blazor100/tree/Blazor-教程15-2/b15blazorIDS

源代码

https://github.com/densen2014/Blazor100

https://gitee.com/densen2014/Blazor100 (镜像/非最新版)