具有属性的基于IP的授权策略

时间:2017-08-16 11:42:38

标签: asp.net-core asp.net-core-mvc .net-core

我试图根据客户端IP来保护REST API。

想象一下包含这些请求示例的博客应用程序:

/post/list               // Everyone     should see the posts
/post/create             // Only Authors should create a post
/post/update/42          // Only Authors should update a post
/post/delete/42          // Only Admins  should delete a post
/comment/42/list         // Everyone     should see a post's comments
/comment/42/create       // Everyone     should create a comment
/comment/42/delete/1337  // Only Admins  should delete a comment

appsettings.json 中定义的IP白名单:

"IpSecurity": {
  "Author": "123.456.789.43,123.456.789.44",
  "Admin": "123.456.789.42"
}

以下是我想要实施的符合RequireRole属性的操作示例:

[HttpGet("post/list")]
public List<Post> List()
// ...

[RequireRole("Author")]
[HttpGet("post/create")]
public StandardResponse Create([FromBody]Post post)
// ...

[RequireRole("Admin")]
[HttpGet("post/delete/{id}")]
public StandardResponse Delete(int id)
// ...

启动

定义注射剂
var IpSecurity = Configuration.GetSection("IpSecurity");
services.Configure<IpSecurityConfig>(IpSecurity);

这听起来像个好主意吗?

我应该为此做一个自定义授权策略,中间件和/或过滤器吗?

我如何实现RequireRole属性?

This提供了如何实施IP白名单的想法,但由于中间件无法访问上下文操作,因此我无法使用属性来定义我的要求。

3 个答案:

答案 0 :(得分:4)

是的,这看起来不错,因为它看起来很容易理解。

我要提出的一个评论是使用术语&#34;角色&#34;这可能会使你的继任者感到困惑。称之为&#34; MachineRole&#34;代替? (并且出于同样的原因,不要使用[Authorize(Roles="..."]

在AspNetCore中的实现让我觉得它在MVC4下更加复杂,在Startup.cs的常用方法中就像这样:

public void ConfigureServices(IServiceCollection services)
{
    //after services.AddMvc() :

    services.AddAuthorization(o => { o.AddPolicy(MachineRole.AuthorMachine, p => p.RequireClaim(nameof(MachineRole), MachineRole.AuthorMachine));  });
    services.AddAuthorization(o => { o.AddPolicy(MachineRole.AdminMachine,  p => p.RequireClaim(nameof(MachineRole), MachineRole.AdminMachine)); });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    // ...

    app.UseClaimsTransformation( AddMachineRoleClaims );

    // app.UseMvc( ... );
    // ...etc...
}

public Task<ClaimsPrincipal> AddMachineRoleClaims(ClaimsTransformationContext ctx)
{
    var connectionRemoteIpAddress = ctx.Context.Connection.RemoteIpAddress.MapToIPv4();
    if (Configuration.GetSection("IpSecurity")["Author"].Contains(connectionRemoteIpAddress.ToString()))
    {
        ctx.Principal.AddIdentity(new ClaimsIdentity(new[] { new Claim(nameof(MachineRole), MachineRole.AuthorMachine) }));
    }
    if (Configuration.GetSection("IpSecurity")["Admin"].Contains(connectionRemoteIpAddress.ToString()))
    {
        ctx.Principal.AddIdentity(new ClaimsIdentity(new[] { new Claim( nameof(MachineRole), MachineRole.AdminMachine) }));
    }

    return Task.FromResult(ctx.Principal);
}

public static class MachineRole
{
    public const string AuthorMachine = "AuthorMachine";
    public const string AdminMachine = "AdminMachine";
}

然后你可以使用

[Authorize(Policy = MachineRole.AdminMachine)]

答案 1 :(得分:1)

我对这不是一件简单的事情感到非常恼火,尤其不像MVC4那样简单,我已经完成了https://github.com/chrisfcarroll/RequireClaimAttributeAspNetCore以使其成为可能:

Sub TestCOMtoAccess()

    ' Has References to Microsoft Access Object Library & Microsoft DAO 3.6 Object Library

    Dim oAccess As Access.Application
    Dim oForm As Access.Form
    Dim RS As DAO.Recordset

    ' This assumes that exactly one instance of Access is running, with your old application
    Set oAccess = GetObject(, "Access.Application")
    Set oForm = oAccess.Forms("your_giant_form")

    ' find the record you are looking for
    Set RS = oForm.RecordsetClone
    RS.FindFirst "myPrimaryKey = 42"
    ' and navigate the form to this record
    If Not RS.NoMatch Then
        oForm.Bookmark = RS.Bookmark
    End If
    RS.Close

End Sub

答案 2 :(得分:0)

假设您已经考虑过基于IP的授权的含义 - 这样它们可能会被欺骗,并且请求会在被拒绝之前将其非常深入到您的堆栈中...

我建议创建一个分配声明的中间件,或者至少设置身份(以便用户通过身份验证)。然后使用任一声明(您已分配给中间件中的标识)或授权策略(https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies)。然后,您可以根据与策略关联的IP拒绝每个请求:

[Authorize(Policy="AuthorIp")]
[HttpGet("post/create")]
public StandardResponse Create([FromBody]Post post)