编写可扩展的OWIN身份验证

时间:2017-03-27 16:34:44

标签: security asp.net-web-api2 owin reusability

我正在开发一组Web服务。我已根据公司的安全性实施了自定义OWIN身份验证,因此现在授权属性可以正常运行。

[Authorize]// It's working!

我想将其打包给其他人,但我想首先支持角色(或者至少有一个关于如何支持角色的计划/建议)。不幸的是,我的公司没有标准的角色处理方式,因此不同的服务(或应用程序)可能采用不同的方法。

[Authorize("Member")]// It's not working. :(

使我的身份验证中间件易于扩展的最佳方法是什么?我的特殊需求是面向支持角色,但更通用的东西很好。我有过一些想法:

  • 我可以期待他们扩展我的身份验证。
    • 这需要开发人员进行更多维护。
    • 在制作我可以重复使用的内容时删除大部分值。
  • 我可以提供要挂钩的活动。
    • 许多预先构建的身份验证似乎都是这样做的。他们在他们的选项中接受提供者,并且该提供者支持少数事件。
      • 我不熟悉这种方法;我不确定这是否是最佳解决方案。
      • 我当前的选项对象是空的(就像许多教程一样),我对改变它感到犹豫。
    • 我之前没有写过(并且几乎没有消耗过)任何事件,所以这对我个人来说将是一个新的领域。

我倾向于后一种方法,但我真的只是在黑暗中拍摄。我非常感谢能够确认哪些有效或最有效。

1 个答案:

答案 0 :(得分:0)

要支持[授权("会员")]等自定义属性,您可以扩展属性并编写自定义属性。扩展System.Web.Http.AuthorizeAttribute类并执行您需要执行的所有检查。

这解释了如何做到这一点:

https://www.codeproject.com/Tips/376810/ASP-NET-WEB-API-Custom-Authorize-and-Exception-Han

这是我们解决方案中的一个实现。

public class ClaimsAuthorize : System.Web.Mvc.AuthorizeAttribute
    {
        public string PhenixPermissions { get; set; }
        public string[] NeededPermissions;

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            Logger.Logger.Trace("ClaimsAuthorize.AuthorizeCore");

            NeededPermissions = PhenixPermissions.Split(',');

            if (!(httpContext.User.Identity is ClaimsIdentity))
            {
                return false;
            }

            var claimsIdentity = httpContext.User.Identity as ClaimsIdentity;
            Claim encodedPermissions = claimsIdentity.FindFirst(ConfigurationManager.AppSettings["ApplicationPermissionsKey"]);
            string applicationId = ClaimsHelper.GetClaimValue("audience");

            if (encodedPermissions == null)
            {
                Logger.Logger.Warn("No PhenixPermissions found. Are you logged in?");
                return false;
            }

            var tenant = AppManager.GetApplication(applicationId);

            List<string> decodedPermissions = PermissionsDecodeHelper.BitDecodePermissions(tenant.ConnectionString, encodedPermissions.Value);

            bool hasRights = false;

            foreach (var neededPermission in NeededPermissions)
            {
                if (decodedPermissions.FirstOrDefault(x => x == neededPermission) != null)
                {
                    Logger.Logger.Debug(string.Format("User '{0}' authorized to access view '{1}'.", claimsIdentity.Name.ToString(), httpContext.Request.FilePath));
                    hasRights = true;
                }
            }

            return hasRights;
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            Logger.Logger.Trace("ClaimsAuthorize.HandleUnauthorizedRequest");

            Logger.Logger.Warn(string.Format("Unauthorized to access '{0}'.", filterContext.Controller));

            filterContext.Controller.TempData["ErrorCode"] = "0123456789";
            filterContext.Controller.TempData["ErrorMessage"] = string.Format("'{0}' is not authorized to access access view '{1}'", HttpContext.Current.User.Identity.Name.ToString(), filterContext.Controller);

            filterContext.Result = new RedirectResult("~/Home/Error");
        }
    }

一些评论:PhenixPermissions是使用[ClaimsAuthorize(PhenixPermissions =&#34; ConsultExternalLink&#34;)]等属性时出现的字符串。

其余的是我们的应用程序的一些特定逻辑,但你应该得到它。

当允许调用Controller,API等时,只需返回AuthorizeCore true或false ......

希望这有帮助