我试图根据客户端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白名单的想法,但由于中间件无法访问上下文操作,因此我无法使用属性来定义我的要求。
答案 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)