You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在多层架构Blazor应用中将授权能力扩展至数据访问类库

实现方案

你可以通过以下两种方式将授权校验下沉到数据访问类库,和Blazor页面的[Authorize]特性使用逻辑保持一致:


前置准备

1. 类库安装依赖

给你的.NET Standard 2.0类库安装以下NuGet包:

  • Microsoft.AspNetCore.Authorization:提供[Authorize]特性定义
  • Microsoft.AspNetCore.Http.Abstractions:提供身份信息访问的基础抽象
  • (如果用AOP方案)额外安装AspectCore.Extensions.DependencyInjection

2. Blazor端补充注册

修改Blazor应用的Startup.cs,补充注册身份相关服务:

public void ConfigureServices(IServiceCollection services)
{
    // 原有其他服务注册
    services.AddHttpContextAccessor();
    // Blazor服务端默认已注册AuthenticationStateProvider,无需额外添加
    
    // 原有类库服务注册
    services.AddTransient<ISqlDataAccess, SqlDataAccess>();
    services.AddTransient<IPeopleData, PeopleData>();
}

如果采用AOP方案,需要修改Program.cs启用动态代理容器:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseServiceProviderFactory(new DynamicProxyServiceProviderFactory()) // 新增这行
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

方案1:手动权限校验(轻量无第三方依赖)

适合类库方法数量少的场景,不需要额外框架,直接在方法内嵌入校验逻辑:

改造数据访问类

以PeopleData.cs为例:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;

public class PeopleData : IPeopleData
{
    private readonly ISqlDataAccess _db;
    private readonly IHttpContextAccessor _httpContextAccessor;
    // Blazor服务端可替换为 AuthenticationStateProvider 获取用户更稳定
    // private readonly AuthenticationStateProvider _authStateProvider;

    public PeopleData(ISqlDataAccess db, IHttpContextAccessor httpContextAccessor)
    {
        _db = db;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task<List<PersonModel>> GetAllPeople()
    {
        // 权限校验逻辑
        var user = _httpContextAccessor.HttpContext?.User;
        // Blazor服务端用以下代码取用户
        // var authState = await _authStateProvider.GetAuthenticationStateAsync();
        // var user = authState.User;
        
        if (user == null || !user.Identity.IsAuthenticated)
        {
            throw new UnauthorizedAccessException("用户未登录");
        }
        if (!user.IsInRole("admin"))
        {
            throw new UnauthorizedAccessException("当前用户无管理员权限");
        }

        string sql = "select * from dbo.People";
        return await _db.LoadData<PersonModel, dynamic>(sql, new { }); 
    }
}

方案2:AOP自动拦截(和Blazor页面用法一致)

适合类库方法多的场景,自动识别类/方法上的[Authorize]特性完成校验,不需要每个方法手写校验逻辑:

1. 自定义授权拦截器

using AspectCore.DynamicProxy;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;

public class AuthorizeInterceptor : AbstractInterceptor
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    // Blazor服务端替换为:
    // private readonly AuthenticationStateProvider _authStateProvider;

    public AuthorizeInterceptor(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public override async Task Invoke(AspectContext context, AspectDelegate next)
    {
        // 优先读取方法上的[Authorize]特性,没有则读取类上的
        var authAttribute = context.ImplementationMethod.GetCustomAttribute<AuthorizeAttribute>()
            ?? context.ImplementationType.GetCustomAttribute<AuthorizeAttribute>();

        if (authAttribute != null)
        {
            var user = _httpContextAccessor.HttpContext?.User;
            // Blazor服务端取用户代码:
            // var authState = await _authStateProvider.GetAuthenticationStateAsync();
            // var user = authState.User;
            
            if (user == null || !user.Identity.IsAuthenticated)
            {
                throw new UnauthorizedAccessException("未登录用户禁止访问");
            }

            // 校验角色
            if (!string.IsNullOrEmpty(authAttribute.Roles))
            {
                var roles = authAttribute.Roles.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
                if (!roles.Any(user.IsInRole))
                {
                    throw new UnauthorizedAccessException("用户无对应角色权限");
                }
            }

            // 若需要校验授权策略,可补充以下逻辑
            // if (!string.IsNullOrEmpty(authAttribute.Policy))
            // {
            //     var authService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
            //     var authResult = await authService.AuthorizeAsync(user, authAttribute.Policy);
            //     if (!authResult.Succeeded) throw new UnauthorizedAccessException("用户无对应策略权限");
            // }
        }

        await next(context);
    }
}

2. 注册拦截器

修改Startup.cs的服务注册部分,给需要拦截的类库服务加上拦截器:

// 注册拦截器
services.AddTransient<AuthorizeInterceptor>();
// 给类库服务配置动态代理,绑定拦截器
services.AddTransient<IPeopleData, PeopleData>().ConfigureDynamicProxy(p => p.AddInterceptor<AuthorizeInterceptor>());
// 其他类库服务也可以按同样方式绑定拦截器

3. 直接加特性使用

现在你就可以直接在类库的类或者方法上加[Authorize]特性,和Blazor页面的用法完全一致:

public class PeopleData : IPeopleData
{
    private readonly ISqlDataAccess _db;

    public PeopleData(ISqlDataAccess db)
    {
        _db = db;
    }

    // 加在方法上仅对当前方法生效,加在类上对类所有方法生效
    [Authorize(Roles = "admin")]
    public Task<List<PersonModel>> GetAllPeople()
    {
        string sql = "select * from dbo.People";
        return _db.LoadData<PersonModel, dynamic>(sql, new { }); 
    }
}

内容的提问来源于stack exchange,提问作者jason

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 07:48:03