asp.net授权(2)

若没有看过上一篇文章,请先看一下上一篇文章

基于角色的授权(RBAC)

自定义认证处理器(认证逻辑有变化)

using System.Security.Claims;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;

namespace CustomAuthentication.AuthenticationHandlers;


//自定义选项
public class SecretAuthenticationOptions : AuthenticationSchemeOptions
{
    //自定义方案名
    public const string Scheme = "Secret";
}

//自定义角色
public static class SecretRoles
{
    //小红的朋友
    public const string XiaoHongFriend = "XiaoHongFriend";

    //小红的爱慕者
    public const string XiaoHongAdorer = "XiaoHongAdorer";
}

public class SecretAuthenticationHandler : AuthenticationHandler<SecretAuthenticationOptions>
{
    public SecretAuthenticationHandler(IOptionsMonitor<SecretAuthenticationOptions> options, ILoggerFactory logger,
        UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
    {
    }

    private Task<AuthenticateResult> createSingleIdentityAuthenticationTicket(IEnumerable<Claim> claims)
    {
        //创建主体
        var claimsPrincipal = new ClaimsPrincipal();
        //创建证件
        var claimsIdentity = new ClaimsIdentity();
        //为证件添加信息
        claimsIdentity.AddClaims(claims);
        //为主体添加证件
        claimsPrincipal.AddIdentity(claimsIdentity);
        //返回认证票据
        return Task.FromResult(
            AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal, SecretAuthenticationOptions.Scheme)));
    }


    //小红的朋友
    private string[] xiaohongFriends = { "小红", "小芳", "小樱","小华" };

    //小红的爱慕者
    private string[] xiaohongAdorers = { "小明", "小李", "小华" };

    //具体认证过程
    //若该方案是默认方案,无论任何时候(action存不存在,有没有标注Authorize特性),该方法都会执行
    //若不是默认方案,则仅在标注了Authorize特性,并指定了该方案的情况下,该方法才会执行
    //若认证成功,会将返回值中的claimsPrincipal赋值给HttpContext.User,后续在action中可以访问
    //ClaimTypes.Role为预定义的Claim类型
    //ClaimTypes.Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var nameStringValues = Request.Query["name"];
        if (nameStringValues.Count != 1) return Task.FromResult(AuthenticateResult.NoResult());

        var name = nameStringValues.ToString();
        
        var claims = new List<Claim>(3);
        if (xiaohongFriends.Contains(name)) claims.Add(new Claim(ClaimTypes.Role,SecretRoles.XiaoHongFriend));
        if (xiaohongAdorers.Contains(name)) claims.Add(new Claim(ClaimTypes.Role,SecretRoles.XiaoHongAdorer));
        
        if(claims.Count == 0) return Task.FromResult(AuthenticateResult.NoResult());
        
        claims.Add(new Claim("name",name));
        
        return createSingleIdentityAuthenticationTicket(claims);
    }
}

Or

[Route("[controller]/[action]")]
public class SecretSpaceController : ControllerBase
{
    //小红的朋友或小红的爱慕者都可访问
    [Authorize(Roles = $"{SecretRoles.XiaoHongFriend},{SecretRoles.XiaoHongAdorer}")]
    [HttpGet]
    public string OrSecret1() => $"{HttpContext.User.FindFirst("name")?.Value ?? "无名"}知道了小明喜欢小红";
}

And

[Route("[controller]/[action]")]
public class SecretSpaceController : ControllerBase
{   
    //同时是小红的朋友和小红的爱慕者才可以访问(只有小华可以)
    [Authorize(Roles = SecretRoles.XiaoHongAdorer)]
    [Authorize(Roles = SecretRoles.XiaoHongFriend)]
    [HttpGet]
    public string AndSecret1() => $"{HttpContext.User.FindFirst("name")?.Value ?? "无名"}知道了小明喜欢小红";
}

基于策略的授权

Program.cs添加AddAuthorization

//添加授权策略
builder.Services.AddAuthorization(options =>
{
    //若Authorize特性中没有指定策略和角色,则使用该策略
    options.DefaultPolicy = new AuthorizationPolicyBuilder().RequireRole(SecretRoles.XiaoHongAdorer,SecretRoles.XiaoHongFriend).Build();
    //添加策略
    options.AddPolicy("策略名", authorizationPolicyBuilder =>
    {
        //使用AuthorizationPolicyBuilder添加具体策略
    });
});

自定义授权处理器

同时实现AuthorizationHandler和IAuthorizationRequirement

using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;

namespace CustomAuthentication.AuthorizationHandlers;

public class SecretAuthorizationHandler : AuthorizationHandler<SecretAuthorizationHandler>,IAuthorizationRequirement
{
    private readonly string[] roles;
    
    public SecretAuthorizationHandler(params string[] roles)
    {
        this.roles = roles;
    }
    
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SecretAuthorizationHandler requirement)
    {
        if (context.User.Claims.Where(claim => claim.Type == ClaimTypes.Role).Any(claim => requirement.roles.Contains(claim.Value)))
        {
            context.Succeed(requirement);
            return Task.CompletedTask;
        }
        context.Fail();
        return Task.CompletedTask;
    }
}
	options.AddPolicy("RolesPolicy", authorizationPolicyBuilder =>
    {
        //对于每个Requirement,若有一个处理器调用了context.Fail()或没有任何处理器调用了context.Succeed(Requirement),则该Requirement检验失败,否则检验成功
        //若所有的Requirement都检验成功,则授权成功,否则授权失败
        //这里添加了2个Requirement和2个Handler,每个Requirement都需要被所有Handler处理,总共调用了4次
        authorizationPolicyBuilder.AddRequirements(new SecretAuthorizationHandler(SecretRoles.XiaoHongAdorer));
        authorizationPolicyBuilder.AddRequirements(new SecretAuthorizationHandler(SecretRoles.XiaoHongFriend));
    });
	[Authorize(Policy = "RolesPolicy")]
    [HttpGet]
    public string Secret1() => $"{HttpContext.User.FindFirst("name")?.Value ?? "无名"}知道了小明喜欢小红";
    

分别实现AuthorizationHandler和IAuthorizationRequirement

public class SecretAuthorizationRequirement : IAuthorizationRequirement
{
    public IEnumerable<string> Roles { get; set; }
}

public class SecretAuthorizationHandler : AuthorizationHandler<SecretAuthorizationRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SecretAuthorizationRequirement requirement)
    {
        if (context.User.Claims.Where(claim => claim.Type == ClaimTypes.Role)
            .Any(claim => requirement.Roles.Contains(claim.Value)))
        {
            context.Succeed(requirement);
            return Task.CompletedTask;
        }

        context.Fail();
        return Task.CompletedTask;
    }
}
builder.Services.AddSingleton<IAuthorizationHandler,SecretAuthorizationHandler>();
	options.AddPolicy("RolesPolicy", authorizationPolicyBuilder =>
    {
    	//对于每个Requirement,若有一个处理器调用了context.Fail()或没有任何处理器调用了context.Succeed(Requirement),则该Requirement检验失败,否则检验成功
        //若所有的Requirement都检验成功,则授权成功,否则授权失败
        authorizationPolicyBuilder.AddRequirements(new SecretAuthorizationRequirement { Roles = new []{SecretRoles.XiaoHongAdorer} });
        authorizationPolicyBuilder.AddRequirements(new SecretAuthorizationRequirement { Roles = new []{SecretRoles.XiaoHongFriend} });
    });

直接实现IAuthorizationHandler,处理多个Requirement

public class SecretAuthorizationHandler : IAuthorizationHandler
{
    public async Task HandleAsync(AuthorizationHandlerContext context)
    {
        //context.Requirements => 所有的Requirement
        //context.PendingRequirements => 所有未被标记为succeeded的Requirement
        //AuthorizationHandler<IAuthorizationRequirement>也是在此方法内根据Requirement的类型判断是否调用HandleRequirementAsync
        
        //后面再根据Requirement的具体类型进行分别处理...
    }
}

AuthorizationPolicyBuilder中的其他方法

	options.AddPolicy("RolesPolicy", authorizationPolicyBuilder =>
    {
        //和在Authorize特性中指定方案名效果一样
        authorizationPolicyBuilder.AddAuthenticationSchemes(SecretAuthenticationOptions.Scheme);
        
        //以下方法内部都是利用前面的方法实现的
        authorizationPolicyBuilder.RequireRole(SecretRoles.XiaoHongAdorer,SecretRoles.XiaoHongFriend);
        authorizationPolicyBuilder.RequireClaim(ClaimTypes.Role);
        authorizationPolicyBuilder.RequireClaim(ClaimTypes.Role,SecretRoles.XiaoHongAdorer,SecretRoles.XiaoHongFriend);
        authorizationPolicyBuilder.RequireAssertion(authorizationHandlerContext =>
        {
            //利用authorizationHandlerContext做一些判断
            return false;
        });
    });

策略提供器(实现动态策略)

public class CustomAuthorizationPolicyProvider : IAuthorizationPolicyProvider
{
    //默认策略提供器
    private IAuthorizationPolicyProvider defaultPolicyProvider;
    
    public CustomAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options)
    {
        defaultPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
    }
    
    public async Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
    {
        var policy = await defaultPolicyProvider.GetPolicyAsync(policyName);
        if (policy is not null)
        {
            //如果策略是硬编码的,由默认策略提供器处理就行
            return policy;
        }

        var builder = new AuthorizationPolicyBuilder();
        
        //根据策略名对builder做些处理...

        return builder.Build();
    }

    public Task<AuthorizationPolicy> GetDefaultPolicyAsync() => defaultPolicyProvider.GetDefaultPolicyAsync();

    public Task<AuthorizationPolicy?> GetFallbackPolicyAsync() => defaultPolicyProvider.GetFallbackPolicyAsync();
}
builder.Services.AddSingleton<IAuthorizationPolicyProvider,CustomAuthorizationPolicyProvider>();

基于资源的授权

using Microsoft.AspNetCore.Authorization;

namespace CustomAuthentication.AuthorizationHandlers;

public class SameAuthorRequirement : IAuthorizationRequirement { }

public class Document
{
    public long Id { get; set; }
    public string Author { get; set; }
}

public class DocumentAuthorizationHandler : 
    AuthorizationHandler<SameAuthorRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
        SameAuthorRequirement requirement,
        Document resource)
    {
        if (context.User.Identity?.Name == resource.Author)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("DocumentPolicy", policy =>
        policy.Requirements.Add(new SameAuthorRequirement()));
});

builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
	[HttpGet]
    public async Task<string> GetAuthor([FromQuery] int id,[FromServices] IAuthorizationService authorizationService)
    {
        Document document = null;
        
        //根据id从数据库查询得到document
        //document = ....

        //授权结果
        var authorizeResult = await authorizationService.AuthorizeAsync(HttpContext.User, document, "DocumentPolicy");
        
        if (authorizeResult.Succeeded)
        {
            //授权成功...
        }
        else
        {
            //授权失败...
        }

        return "";
    }

有扩展重载方法IAuthorizationService.AuthorizeAsync(user , policy),不需要传入资源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值