我有一个WCF服务,它返回一个实现IPrinciple和IIdentity的对象。
我认为无论如何我都可以将其连接到MVC3授权系统而无需创建RoleProvider
e.g。所以我可以在我的AccountController登录方法中做这样的事情:
// AthenticatedUser implments both IPrinciple and IIdentity
AthenticatedUser user = wcfService.Logon(password, userName);
FormsAuthentication.SetAuthCookie(userName, false);
// Set IPrinciple so I can use IsInRole method elsewhere (or AuthorizationAttribute can reuse it)
this.HttpContext.User = authenticationClient.AuthenticatedUser;
然后在我使用时使用
[Authorize (Roles = "foo", "bar")]
我的AuthenticatedUser的IsInRole方法被调用。
然而,在我的测试/调试中,我发现this.HttpContext.User似乎没有跨请求进行维护。
编辑抱歉:我应该已经明确表示我不想在每个请求上调用我的WCF服务,我想以某种方式缓存/存储用户和角色,并且能够使用AuthorizeAttribute与IPrinciple来自我的服务。
有人可以帮忙吗?提前谢谢!
答案 0 :(得分:3)
如果您使用IIS 7在本地计算机上运行此命令,请将其添加到system.webServer下的web.config:
<modules runAllManagedModulesForAllRequests="true">
<remove name="FormsAuthentication" />
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
<remove name="UrlAuthorization" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
<remove name="DefaultAuthentication" />
<add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" />
<remove name="RoleManager" />
<add name="RoleManager" type="System.Web.Security.RoleManagerModule" />
</modules>
答案 1 :(得分:2)
你说“this.HttpContext.User似乎没有跨请求维护” - 这是正确的行为。每个请求都有一个唯一的HttpContext
。
您可能想要尝试的是:
FormsAuthentication.SetAuthCookie(userName, true);
,它会在浏览器会话之间创建一个持久的cookie。
答案 2 :(得分:1)
如您所知,HttpContext
不会在请求中保留,因此IPrincipal
和IIdentity
都不会 - HttpContext
在每个请求开始时构建通过框架,IPrincipal
和IIdentity
是从身份验证cookie反序列化的身份验证票证构建的。
您所描述的内容在某些方面与 WCF authentication service 听起来相似。在这种情况下,服务将对用户进行身份验证,并在对调用应用程序的响应中发回一个身份验证cookie,然后该应用程序将使用cookie在每个后续请求中构造IPrincipal
和IIdentity
您可以在引发IPrincipal
事件时覆盖IIdentity
和Application.PostAuthenticateRequest
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
if (Context.User != null)
{
var identity = Context.User.Identity;
// define our own IIdentity and IPrincipal for an authenticated user
if (identity.IsAuthenticated)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
var ticket = FormsAuthentication.Decrypt(authCookie.Value);
// get the roles from somewhere
var roles = GetRoles();
identity = new CustomIdentity(ticket.Name);
IPrincipal principal = new CustomPrincipal(identity, roles);
Context.User = Thread.CurrentPrincipal = principal;
}
}
}
您可以看到需要从某个位置检索角色。有了RoleProvider,这些角色可以缓存在另一个cookie中。 如果你知道你在做什么的安全性,你可以考虑复制角色在cookie中的序列化和加密方式。
另一种选择可能是将角色存储在会话中,并且可能适用于少量角色。请注意,在PostAcquireRequestState
事件被提出之前,会话不可用,有些 7 events later in the application request lifecycle 而不是PostAuthenticateRequest
。
答案 3 :(得分:0)
可以在AuthenticateRequest事件中对您的全局asax做出反应,并像这样更改IIdentity:
public class MvcApplication : System.Web.HttpApplication
{
public override void Init()
{
base.Init();
this.AuthenticateRequest += new EventHandler(MvcApplication_AuthenticateRequest);
}
void MvcApplication_AuthenticateRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Request.IsAuthenticated)
{
var name = HttpContext.Current.User.Identity.Name;
var key = "User-" + name;
var principal = HttpContext.Current.Cache["User-" + name];
if (principal == null)
{
principal = GetYourUserAsIPrincipal();
// Add to cache for 1 hour with sliding expiration
HttpContext.Current.Cache.Insert(key, principal, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(1, 0, 0));
}
HttpContext.Current.User = principal ;
}
}
}
编辑:对于缓存,您可以使用默认的ASP.NET缓存。我编辑了上面的示例。注意,ASP.NET缓存是线程安全的(http://msdn.microsoft.com/en-us/library/system.web.caching.cache.aspx)
如果将所有缓存访问逻辑包装到单个类中,那将是最好的。
与任何缓存机制一样:如果更改用户角色,则仅在缓存过期时才会反映出来。