如何设计控制器动作以响应猜测和授权用户

时间:2016-10-31 01:20:13

标签: c# asp.net-mvc authentication

我的控制器设计中有一个操作,用户已在我的系统中注册:

 [Authorize]
 public ActionResult getUserData()
 {
      string UserId = User.Identity.GetUserId();
      return getDataFromDB(UserID);
 }

工作正常。如果您尚未通过身份验证,也会重定向到LOGIN页面。

但我也想为访问该页面的匿名用户提供一个虚拟函数getFakeData(),以便他们可以看到该页面的演示。

我应该在哪里进行验证以查看用户是否经过身份验证并更改行为?

  1. 在网页上,我可以根据用户身份验证来设置dataUrl。我可以在没有[Authorize]标记

    的情况下创建一个单独的函数
    @if (Request.IsAuthenticated)
    {
         dataUrl = '=/Project/Controller/getUserData'
    } else {
         dataUrl = '=/Project/Controller/getFakeData'    
    }
    
  2. 或者我可以在同一个操作控制器上执行此操作并检查用户是否已通过身份验证?但不确定是否可行。

  3. 或者是更好的方法吗?

1 个答案:

答案 0 :(得分:1)

有多种方法可以做到这一点,但这是我的建议

// For ASP.Net MVC 5 simply inherit from AuthorizationAttribute and override the methods.
public class AccessControlAttribute : Attribute, IAuthorizationFilter
{
    private readonly Roles role;
    public AccessControlAttribute(Roles role) {
        this.role = role;
    }
    private Boolean AuthorizationCore(AuthorizationFilterContext context) {
        var username = context.HttpContext.Request.Cookies["loginCookie_username"];
        var password = context.HttpContext.Request.Cookies["loginCookie_password"];
        if (role == Roles.FakeFullAccess) {
            username = "FAKE";
            goto final;
        }
        //In ASP.Net MVC 5 use Ninject for dependency injection and get the service using : [NinjectContext].GetKernel.Get<DbContext>();
        DbContext db = (DbContext) context.HttpContext.RequestServices.GetService(typeof(DbContext));
        if (username != null && password != null) {
            var findUser = db.Set<Login>().Find(username);
            if (findUser != null && findUser.Password.Equals(password) && findUser.RoleId == (int)role) {
                goto final;
            }
        }
        return false;
        final: {
            context.HttpContext.User.AddIdentity(new System.Security.Principal.GenericIdentity(username));
            return true;
        }   
    }
    private void HandleUnauthorizedRequest(AuthorizationFilterContext context) {
        context.Result = new RedirectToRouteResult(new {
            area = "",
            controller = "",
            action = ""
        });
    }        
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        if (AuthorizationCore(context))
        {
            // If using a combination of roles, you have to unmask it
            if (role == Roles.FakeFullAccess) {
                context.HttpContext.Request.Headers.Add("Render", "FakeAccess");
            }
            else if (role == Roles.Admin)
            {
                context.HttpContext.Request.Headers.Add("Render", "AdminAccess");
            }
        }
        else {
            HandleUnauthorizedRequest(context);
        }
    }

}
[Flags]
public enum Roles
{
    FakeFullAccess = 0, 
    ReadOnly = 1,
    Admin = 2,
    Supervisor = 1 << 2,
    AnotherRole = 1 << 3
}

在您的视图中,您可以阅读添加的标题并自定义视图(在ASP.Net Core中,无法访问ControllerContext和ViewBag,如​​果使用ASP.Net MVC 5则不需要使用标题技巧)

// For ASP.Net MVC 5 use the ViewBag or ViewData
@Html.Partial(HttpContext.Request.Header["Render"])
//Assuming this renders the menu with proper functions.

现在,您拥有完全可自定义的基于角色的身份验证系统,可以进行虚假访问以进

<强>更新 要使用该属性,请执行以下操作

[AccessControl(Role.Admin)]
public TestController: Controller {
    ...
}
// Dedicated for testing
[AccessControl(Role.FakeAccess)]
public PreviewController: TestCoontroller{}

如果需要,您还可以组合角色,例如[AccessControl(Role.FakeAccess | Role.ReadOnly)],但您必须实施取消屏蔽方法。