ASP.NET MVC 5 中的身份验证和授权

Authentification and Authorization in ASP.NET MVC 5

我对 ASP.NET MVC 5 中的身份验证和授权感到很困惑。

我在现有网站上工作,我需要在其中添加安全性。我所说的安全是指身份验证(登录)和授权(角色)。我可以访问 Web 服务,但不能直接访问数据库,尽管我可以访问实体(用户、角色等)。

Membership Provider 似乎有点老了,所以我看了一下 Identity,但在现有项目中实施它看起来很复杂,尤其是当我无法直接访问数据库时。

什么是好的解决方案?最佳做法是什么? 你能建议我任何好的资源,这样我就可以满足我的需要吗?

谢谢。

如果有人像我一样感到迷茫,这里有一个使用 Claims 的潜在解决方案。最后,您将了解如何处理身份验证、授权和角色。 希望能帮到你。

启动配置

在项目的根文件夹中,我创建了一个文件 startup.cs。她包含一个部分 class,我们将使用它来配置应用程序以使用存储签名用户的 cookie。

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
    }
}

然后,在 App_Start 我有一个文件,Startup.Auth.cs

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login")                
        });
    }
}

控制器

首先,我创建了一个具有 IAuthenticationManager 类型属性的 AcountController.cs。此属性获取当前请求可用的身份验证中间件功能。

public class CompteController : Controller
{ 
    private IAuthenticationManager AuthenticationManager
    {
        get
        {
            return HttpContext.GetOwinContext().Authentication;
        }
    }
}

然后,我有一个名为 Login with GET 和 POST 的 classic 视图。在 post 中,如果用户可以登录,我会检查我的 Web 服务。如果他可以,我会调用一个魔术函数来进行身份验证。在此代码中,class 用户是我在 Web 服务中获得的自定义用户。他没有实现 IUser。

private void AuthentifyUser(User user, bool isPersistent)
{  
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);

    CustomIdentity identity = new CustomIdentity(user);
    CustomPrincipal principal = new CustomPrincipal(identity);
    Thread.CurrentPrincipal = principal;

    AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

我的控制器中最后一个重要的方法允许用户注销。

public ActionResult Deconnexion()
{
    AuthenticationManager.SignOut();
    return RedirectToAction("Login", "Account");
}

索赔

CustomIdentity 和 CustomPrincipal 是我用于声明系统的两个自定义 class。它们间接实现了 IIdentity 和 IPrincipal。我把它们放在一个单独的新文件夹中。

-请记住,委托人对象代表代码 运行 代表的用户的安全上下文,包括该用户的身份 (IIdentity) 和他们所属的任何角色。

-一个身份对象代表代码为运行.

的用户
public class HosteamIdentity : ClaimsIdentity
{
    public HosteamIdentity(User user)
        : base(DefaultAuthenticationTypes.ApplicationCookie)
    {
        AddClaim(new Claim("IdUser", user.Id.ToString()));           
        AddClaim(new Claim(ClaimTypes.Name, user.Name));
        AddClaim(new Claim(ClaimTypes.Role, user.Role));
    }

    public int IdUser 
    { 
        get
        {
            return Convert.ToInt32(FindFirst("IdUser").Value);
        }
    }

    //Other Getters to facilitate acces to the Claims.
}

委托人允许我们访问身份。

public class HosteamPrincipal : ClaimsPrincipal
{
    private readonly HosteamIdentity _identity;
    public new HosteamIdentity Identity
    {
        get { return _identity; }
    }


    public HosteamPrincipal(HosteamIdentity identity)
    {
        _identity = identity;
    }  

    public override bool IsInRole(string role)
    {
        return _identity.Role == role;
    }
}

访问 CustomPrincipal

现在,我将转到 gGlobal.asax,在这里我们将覆盖 Application_PostAuthenticateRequest 事件。当安全模块确定了用户的身份时,将触发此事件。

我们将使用Thread.CurrentPrincipal,这个静态对象获取或设置线程的当前主体(用于基于角色的安全性),因此它非常适合我们的情况!

您可能需要调整此处的代码。我个人必须请求我的网络服务,这可能不是你的情况。

简单谈谈我们的构造函数。拳头是空的,我们不关心角色的时候就用它

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        if (HttpContext.Current.User.Identity.IsAuthenticated)
        {
           Thread.CurrentPrincipal = new HosteamPrincipal(
                new HosteamIdentity(
                    WebService.GetUser(
                        HttpContext.Current.User.Identity.Name)));            
        }
    }

在大多数情况下,通过 is Name 检索用户不是一个好的做法。请根据您的解决方案调整上述代码。

授权属性过滤器

现在,如果我们能够轻松判断经过身份验证的用户可以访问哪个控制器或操作,那就太好了。为此,我们将使用过滤器。

过滤器是自定义的 classes,它提供声明式和程序化的方式来向控制器操作方法添加预操作和 post 操作行为。我们将它们用作注释,例如 [Authorize] 是一个过滤器。

因为要解释的东西太多,我会让你看评论,他们很明确。

简单谈谈我们的构造函数。 -第一个是空的,我们不关心Roles的时候会用到。我们通过在 Controller 或 Action 上写注解 [CustomAuthorize] 来访问它。 -第二个,采用角色数组,我们将通过在控制器或动作上编写注释 [CustomAuthorize("Role1", "Role2", etc.)] 来使用它。他会定义哪些Roles访问Controller或者action

public class CustomAuthorize : AuthorizeAttribute
{
    private new string[] Roles { get; set; }


    public CustomAuthorize() { }
    public CustomAuthorize(params string[] roles)
    {
        this.Roles = roles[0].Split(',');
    }


    /// <summary>
    /// Check for Authorizations (Authenticated, Roles etc.)
    /// </summary>
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext.Request.IsAuthenticated)
            if (Roles != null)
            {
                foreach (string role in Roles)
                    if (((HosteamPrincipal)Thread.CurrentPrincipal).IsInRole(role))
                        return true;
                return false;            
            }
            else                    
                return true;
        return false;
    }


    /// <summary>
    /// Defines actions to do when Authorizations are given or declined
    /// </summary>
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (!AuthorizeCore(filterContext.HttpContext))
            HandleUnauthorizedRequest(filterContext);
    }


    /// <summary>
    /// Manage when an Authorization is declined
    /// </summary>
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAuthenticated)
            filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden);
        else
            base.HandleUnauthorizedRequest(filterContext);
    }
}