原理:通过自定义策略授权提供者指定授权策略并传入必要的授权参数。

参考文档:

https://docs.microsoft.com/zh-cn/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-3.1

1 实现Base验证

1.1定义UserInfo类

public class UserInfo

{

    public string UserName { get; set; }

    public string Password { get; set; }

    public IEnumerable<string> Roles { get; set; }

    public int Age { get; set; }

    /// <summary>

    /// 权限

    /// </summary>

    public IEnumerable<string> Permision { get; set; }

    public override string ToString() => UserName;

    public static readonly UserInfo[] AllUsers = {

        new UserInfo

        {

 

            UserName = "daxnet",

            Password = "password",

            Age = 16,

            Roles = new[] { "admin", "super_admin" },

            Permision = new[] { "Time_Read", "Time_Add" },//权限

 

        },

        new UserInfo

        {

 

            UserName = "admin",

            Password = "password",

            Age = 29,

            Roles = new[] { "admin" },

            Permision = new[] { "Time_Read" },

        }

    };

}

 

1.2 定义BasicAuthenticationSchemeOptions类,配置认证方案选项类

public class BasicAuthenticationSchemeOptions: AuthenticationSchemeOptions

{

}

 

1.3 定义BasicAuthenticationHandler类,认证方案处理类

public class BasicAuthenticationHandler: AuthenticationHandler<BasicAuthenticationSchemeOptions>

{

    public BasicAuthenticationHandler(

    IOptionsMonitor<BasicAuthenticationSchemeOptions> options,

    ILoggerFactory logger,

    UrlEncoder encoder,

    ISystemClock clock): base(options, logger, encoder, clock)

    {

 

    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()

    {

        if (!Request.Headers.ContainsKey("Authorization"))

        {

            return Task.FromResult(AuthenticateResult.Fail("没有指定验证头"));

        }

        string authHeader = Request.Headers["Authorization"].ToString();

        if(!authHeader.StartsWith("Basic "))

        {

            return Task.FromResult(AuthenticateResult.Fail("验证头格式错误"));

        }

        var base64EncodedValue = authHeader["Basic ".Length..];

        var userNamePassword = Encoding.UTF8.GetString(Convert.FromBase64String(base64EncodedValue));

        //获取到Authorization验证头携带的用户数据

        var userName = userNamePassword.Split(':')[0];

        var password = userNamePassword.Split(':')[1];

        //使用模拟数据

        var user = UserInfo.AllUsers.FirstOrDefault(u => u.UserName == userName && u.Password == password);

        if (user == null)

        {

            return Task.FromResult(AuthenticateResult.Fail("用户名或者密码错误"));

        }

        var claims = new[]

        {

            new Claim(ClaimTypes.NameIdentifier, user.UserName),

            new Claim(ClaimTypes.Role, string.Join(',', user.Roles)),

            //new Claim(ClaimTypes.UserData, user.Age.ToString()),

            new Claim(ClaimTypes.UserData, string.Join(',', user.Permision)),

        };

        var claimsPrincipal =

            new ClaimsPrincipal(new ClaimsIdentity(

                claims,

                "Basic",

                ClaimTypes.NameIdentifier,

                ClaimTypes.Role));

 

        var ticket = new AuthenticationTicket(claimsPrincipal, new AuthenticationProperties

        {

            IsPersistent = false

        }, "Basic");

        return Task.FromResult(AuthenticateResult.Success(ticket));

    }

}

 

1.4 Startup.cs加入认证方案

在Startup.cs文件里,修改ConfigureServices和Configure方法,加入Authentication的支持。

ConfigureServices:

services.AddAuthentication("Base").AddScheme<BasicAuthenticationSchemeOptions, BasicAuthenticationHandler>("Base", option => { });

Configure:

app.UseAuthentication();

 

2授权

2.1定义PolicyRequirement 类

public class PolicyRequirement:IAuthorizationRequirement

{

    public string PermisionName { get; private set; }

    public PolicyRequirement(string permisionName)

    {

        this.PermisionName = permisionName;

    }

}

 

2.2定义PolicyProvider类

ASP.NET Core 应用使用接口的实现 IAuthorizationPolicyProvider 来检索授权策略。 默认情况下, DefaultAuthorizationPolicyProvider 已注册并使用。 DefaultAuthorizationPolicyProvider 返回 AuthorizationOptions 调用中提供的策略 IServiceCollection.AddAuthorization 。

通过 IAuthorizationPolicyProvider 在应用程序的 依赖关系注入 容器中注册不同的实现来自定义此行为。

public class PolicyProvider : IAuthorizationPolicyProvider

{

    public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }

    public PolicyProvider(IOptions<AuthorizationOptions> options)

    {

        FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);

    }

    public Task<AuthorizationPolicy> GetDefaultPolicyAsync()

    {

        //需要返回GetDefaultPolicyAsync,

        //直接抛出未实现异常会出现不能调用 GetPolicyAsync方法

        return FallbackPolicyProvider.GetDefaultPolicyAsync();

    }

 

    public Task<AuthorizationPolicy> GetFallbackPolicyAsync()

    {

        return FallbackPolicyProvider.GetDefaultPolicyAsync();

    }

 

    public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)

    {

        var policyBuilder = new AuthorizationPolicyBuilder("Base");

        //通过添加PolicyRequirement后会使用PolicyAuthorizationHandler作为授权处理类

        policyBuilder.AddRequirements(new PolicyRequirement(policyName));

        return Task.FromResult(policyBuilder.Build());

        //return Task.FromResult<AuthorizationPolicy>(null);

    }

}

 

2.3 定义PolicyAuthorizationHandler类

public class PolicyAuthorizationHandler : AuthorizationHandler<PolicyRequirement>

{

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement)

    {

        if (context.User != null)

        {

            var identity = context.User.Identity as System.Security.Claims.ClaimsIdentity;

            if (identity == null)

            {

                context.Fail();

                return Task.CompletedTask;

            }

            var permisions = identity.Claims.FirstOrDefault(c => c.Type == ClaimTypes.UserData);

            if (permisions != null && permisions.Value.Split(',').Contains(requirement.PermisionName))

            {

                context.Succeed(requirement);

            }

            else

            {

                context.Fail();

            }

            return Task.CompletedTask;

        }

        return Task.CompletedTask;

    }

}

2.4 定义PolicyAuthorizeAttribute类

public class PolicyAuthorizeAttribute: AuthorizeAttribute

{

    private string permissionName;

    public PolicyAuthorizeAttribute(string permissionName)

    {

        this.PermissionName = permissionName;

    }

    public string PermissionName

    {

        get

        {

            return permissionName;

        }

        set

        {

            permissionName = value;

            Policy = value;

        }

    }

}

 

2.5 Startup.cs注入IauthorizationHandler和IAuthorizationPolicyProvider

ConfigureServices方法:

services.AddSingleton<IAuthorizationHandler, PolicyAuthorizationHandler>();

services.AddSingleton<IAuthorizationPolicyProvider, PolicyProvider>();

Configure方法:

app.UseAuthorization();

 

2.6 添加TimeController,对控制器的方法进行权限控制

[Authorize]

[ApiController]

[Route("[controller]/[action]")]

public class TimeController : ControllerBase

{

    [PolicyAuthorize("Time_Read")]

    public string Read()

    {

        var u = this.User;

        return "read "+DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

    }

    [PolicyAuthorize("Time_Add")]

    public string Add()

    {

        return "add " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

    }

}

 

效果: