简体   繁体   English

asp.net webapi动态授权

[英]asp.net webapi dynamic authorization

I am new to webapi and mvc and I am struggling to find a best practice for handling authorizations dynamically based on roles and ownership of the resource.我是 webapi 和 mvc 的新手,我正在努力寻找基于角色和资源所有权动态处理授权的最佳实践。 For example an account page that should allow employee admins, employee call center or the owning client to Get, Post, Put or Delete account information.例如,应允许员工管理员、员工呼叫中心或拥有客户的帐户页面获取、发布、放置或删除帐户信息。 So an admin and call center employee should be able to Get, Post, Put or Delete any request for any userid, but a client should only be able to perform these actions on resources owned by them.因此,管理员和呼叫中心员工应该能够获取、发布、放置或删除对任何用户 ID 的任何请求,但客户端应该只能对他们拥有的资源执行这些操作。

For example Tom is UserID 10 and Jerry is UserID 20.例如,Tom 是 UserID 10,Jerry 是 UserID 20。

/api/Account/10 should be accessible by any admin, call center or Tom. /api/Account/10 应该可以被任何管理员、呼叫中心或 Tom 访问。 Jerry should be kicked out.杰瑞应该被踢出去。 /api/Account/20 should be accessible by any admin, call center or Jerry. /api/Account/20 应该可以被任何管理员、呼叫中心或 Jerry 访问。 Tom should be kicked out.汤姆应该被踢出去。

In webforms the typical solution is to just check if the user is a client and verify their id against the request.在 webforms 中,典型的解决方案是检查用户是否是客户端并根据请求验证他们的 id。 (I know AuthorizeAttribute is not in webforms, but showing as an example of what it would covert to in webapi/mvc.) (我知道 AuthorizeAttribute 不在 webforms 中,但作为一个例子显示了它在 webapi/mvc 中的隐藏内容。)

    [Authorize(Roles = "Administrator, CallCenter, Client")]
    public string Get(int userID)
    {
        if (Thread.CurrentPrincipal.IsInRole("Client") && Thread.CurrentPrincipal.Identity.userID != userID)
        { 
            //Kick them out of here.
        }
        return "value";
    }

This will work, but it seems like the check for ownership should happen in a single location before it reaches the controller and should be reusable throughout an application.这会起作用,但似乎所有权检查应该在到达控制器之前在单个位置进行,并且应该可以在整个应用程序中重复使用。 I am guessing the best place would either be a custom AuthorizationFilterAttribute or a custom AuthorizeAttribute and maybe create a new role ClientOwner.我猜最好的地方是自定义 AuthorizationFilterAttribute 或自定义 AuthorizeAttribute,并且可能创建一个新角色 ClientOwner。

    [Authorize(Roles = "Administrator, CallCenter, ClientOwner")]
    public string Get(int userID)
    {
        return "value";
    }

Custom AuthorizeAttribute自定义授权属性

    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        //If user is already authenticated don't bother checking the header for credentials
        if (Thread.CurrentPrincipal.Identity.IsAuthenticated) { return; }

        var authHeader = actionContext.Request.Headers.Authorization;

        if (authHeader != null)
        {
            if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) &&
                !String.IsNullOrWhiteSpace(authHeader.Parameter))
            {
                var credArray = GetCredentials(authHeader);
                var userName = credArray[0];
                var password = credArray[1];

                //Add Authentication
                if (true)
                {
                    var currentPrincipal = new GenericPrincipal(new GenericIdentity(userName), null);
                    var user = GetUser(userName);

                    foreach (var claim in user.Cliams)
                    {
                        currentPrincipal.Identities.FirstOrDefault().AddClaim(new Claim(ClaimTypes.Role, claim);
                    }
                    //**************Not sure best way to get UserID below from url.***********************
                    if (user.userTypeID = UserTypeID.Client && user.userID == UserID)
                    {
                        currentPrincipal.Identities.FirstOrDefault().AddClaim(new Claim(ClaimTypes.Role, "ClientOwner"));
                    }
                    Thread.CurrentPrincipal = currentPrincipal;
                    return;
                }
            }
        }

        HandleUnauthorizedRequest(actionContext);
    }}

Can someone point me in the right direction as to the best place to handle the authorization of the individual user?有人可以指出我处理个人用户授权的最佳位置的正确方向吗? Should this still be done in the controller or should I move it to a custom AuthorizationFilterAttribute or a custom AuthorizationAttribute or is there somewhere else this should be handled?这仍然应该在控制器中完成还是应该将它移动到自定义 AuthorizationFilterAttribute 或自定义 AuthorizationAttribute 或者是否应该在其他地方处理? If the proper place is in a custom attribute, then what is the best way to get the userID and should I create a new role like the example above or should I do something different?如果正确的位置在自定义属性中,那么获取用户 ID 的最佳方法是什么,我应该像上面的示例一样创建一个新角色还是应该做一些不同的事情?

This is a common scenario and I am very surprised that I have struggled to find examples of the above scenario.这是一个常见的场景,我很惊讶我一直在努力寻找上述场景的例子。 This leads me to believe that either everyone is doing the check in the controller or there is another term I am not aware of so I am not getting good google results.这让我相信要么每个人都在控制器中进行检查,要么还有另一个我不知道的术语,所以我没有得到好的谷歌结果。

I think you may be getting authorization and permissions confused.我认为您可能对授权权限感到困惑。 "Dynamic authorization" isn't something you ever do. “动态授权”不是你做过的事情。

Authorization is the act of verifying an author.授权是验证作者的行为。

  1. Request claims it is being sent from Alice.请求声称它是从 Alice 发送的。
  2. Request presents a password or authorization token that proves the requester is Alice.请求提供密码或授权令牌,证明请求者是 Alice。
  3. Server verifies that the password or authorization token matches its records for Alice.服务器验证密码或授权令牌是否与 Alice 的记录匹配。

Permissions are the business logic that specifies who can do what in your system.权限是指定谁可以在您的系统中做什么的业务逻辑。

  1. Request is already authorized, and we know it came from Alice.请求已经被授权,我们知道它来自 Alice。
  2. Alice is requesting to delete an important resource. Alice 请求删除重要资源。
  3. Is Alice an administrator? Alice 是管理员吗? If not, tell her she can't do that because she doesn't have permission.如果没有,告诉她她不能这样做,因为她没有得到许可。 (403 Forbidden) (403 禁止)

The built-in [Authorize] attribute lets you optionally specify Roles that are permitted to access a resource.内置的[Authorize]属性让您可以选择指定允许访问资源的Roles That option to specify permissions as part of authorization is slightly misplaced, in my opinion.在我看来,将权限指定为授权的一部分的选项有点错位。

My advice would be to leave authorization as purely the process of verifying the author of a request.我的建议是让授权纯粹是验证请求作者的过程。 The BasicAuthHttpModule described here is close to what you want already. 这里描述的BasicAuthHttpModule已经接近你想要的了。

Non-trivial permissions logic needs to be handled inside of your action body.非平凡的权限逻辑需要在您的操作主体内进行处理。 Here's an example:下面是一个例子:

//Some authorization logic:
//  Only let a request enter this action if the author of
//  the request has been verified
[Authorize]
[HttpDelete]
[Route("resource/{id}")]
public IHttpActionResult Delete(Guid id)
{
    var resourceOwner = GetResourceOwner(id);

    //Some permissions logic:
    //  Only allow deletion of the resource if the
    //  user is both an admin and the owner.
    if (!User.IsInRole("admin") || User.Identity.Name != resourceOwner)
    {
        return StatusCode(HttpStatusCode.Forbidden);
    }

    DeleteResource(id);
    return StatusCode(HttpStatusCode.NoContent);
}

In this example, it would be difficult to convey the permissions logic as an attribute on the action, because the portion of the permissions that compares the current user to the resource owner can only be evaluated after you have actually gotten the resource owner info from your backend storage device.在这个例子中,很难将权限逻辑作为操作的属性来传达,因为将当前用户与资源所有者进行比较的权限部分只能在您实际从您的后端存储设备。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM