>用户必须在每次执行事务时登录才能验证
有人已经没有走到工作站
登录并走开。
>在程序时不能将角色分配给Web服务方法。
它们必须在运行时分配,以便管理员可以
配置此。此信息存储在系统数据库中。
Web客户端是一个single page application (SPA),所以典型的表单身份验证不工作这么好,但我试图重用尽可能多的ASP.NET安全框架,我可以满足要求。自定义的AuthorizeAttribute非常适合需求2确定与Web服务方法相关联的角色。我接受三个参数,应用程序名称,资源名称和操作,以确定与方法相关联的角色。
public class DoThisController : ApiController { [Authorize(Application = "MyApp",Resource = "DoThis",Operation = "read")] public string GetData() { return "We did this."; } }
我覆盖OnAuthorization方法以获取角色并验证用户。由于用户必须针对每个事务进行认证,所以通过在同一步骤中执行认证和授权来减少来回抖动。我通过使用传递HTTP标头中的加密凭证的基本身份验证从Web客户端获取用户凭据。所以我的OnAuthorization方法看起来像这样:
public override void OnAuthorization(HttpActionContext actionContext) { string username; string password; if (GetUserNameAndPassword(actionContext,out username,out password)) { if (Membership.ValidateUser(username,password)) { FormsAuthentication.SetAuthCookie(username,false); base.Roles = GetResourceOperationRoles(); } else { FormsAuthentication.SignOut(); base.Roles = ""; } } else { FormsAuthentication.SignOut(); base.Roles = ""; } base.OnAuthorization(actionContext); }
GetUserNameAndPassword从HTTP头中检索凭据。然后我使用Membership.ValidateUser验证凭据。我有一个自定义成员资格提供程序和角色提供程序插入到一个自定义数据库。如果用户被验证,我然后检索资源和操作的角色。从那里,我使用基本OnAuthorization完成授权过程。这里是它分解的地方。
如果用户被验证,我使用标准表单验证方法在(FormsAuthentication.SetAuthCookie)中记录用户,如果他们失败,我注销它们(FormsAuthentication.SignOut)。但是问题似乎是基于OnAuthorization类没有访问Principal,它被更新,以便IsAuthenticated设置为正确的值。它总是一步之后。我的猜测是,它使用一些缓存的值,不会更新,直到有一个往返的Web客户端。
所以所有这一切导致我的具体问题是,有没有另一种方法设置IsAuthenticated正确的值为当前Principal而不使用Cookie?在我看来,cookie并不真正适用于这种特定的场景,我必须每次验证。我知道IsAuthenticated的原因没有设置为正确的值是我也重写HandleUnauthorizedRequest方法到这:
protected override void HandleUnauthorizedRequest(HttpActionContext filterContext) { if (((System.Web.HttpContext.Current.User).Identity).IsAuthenticated) { filterContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden); } else { base.HandleUnauthorizedRequest(filterContext); } }
这允许我返回Forbidden的状态代码到Web客户端,如果失败是由于授权而不是认证,它可以相应地做出响应。
那么在这种情况下,为当前原则设置IsAuthenticated的正确方法是什么?
解决方法
public override void OnAuthorization(HttpActionContext actionContext) { string username; string password; if (GetUserNameAndPassword(actionContext,password)) { if (!isUserAuthorized(username)) actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden); } else { actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized); } } else { actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest); } }
我开发了自己的方法来验证角色名为isUserAuthorized,我不再使用基本的OnAuthorization,因为它检查当前的原理,看看它是否为认证。 IsAuthenticated只允许获取所以我不知道如何设置它,我似乎不需要当前的原则。测试这个,它工作正常。
仍然有兴趣,如果任何人有一个更好的解决方案,或可以看到任何问题与这一个。