如何在 ASP.Net MVC 应用程序中使用来自 WCF 身份验证服务的身份验证 cookie
Posted
技术标签:
【中文标题】如何在 ASP.Net MVC 应用程序中使用来自 WCF 身份验证服务的身份验证 cookie【英文标题】:How to use authentication cookie from WCF Authentication Service in an ASP.Net MVC application 【发布时间】:2011-02-04 23:16:37 【问题描述】:好的,我没有找到任何适合我的特定场景的文档或教程。
我有一个 ASP.Net MVC Web 应用程序,它将使用 WCF 服务进行一切,包括身份验证和角色(通过 WCF 后端的成员资格提供程序)。
setting up the authentication services 没有问题,但它没有在网络应用程序中设置 cookie。 Login method of the service 的文档表明可以连接 CreatingCookie 事件,但它对客户端没有任何影响(我也在服务端尝试过,同样没有影响)。所以我想出了如何capture the cookie。我试图在客户端上手动设置 auth cookie,但到目前为止它不起作用;由于填充,解密失败,并且客户端无法读取服务器给定的 cookie 值。
有人知道您应该如何使用 WCF 身份验证服务生成的 cookie 吗?我是否只是假设会话全部在 WCF 服务器上进行管理,并在每次页面加载时检查服务上的 IsLoggedIn()?
提前致谢。
【问题讨论】:
通读 MSDN 上的更多文档,我想我的场景不是 MS 想要的;如果您要在网站上使用会员资格,为什么要对服务进行身份验证而不是直接访问数据库,所以看起来网站必须与任何其他客户端一样处理,这意味着手动从标头并自己使用它们(创建主体、身份验证票等,并将它们分配给网站的适当部分,以便可以使用)。将进行更多调查,并希望有答案发布... 【参考方案1】:我最近一直在尝试实现您所描述的相同功能。我已经设法让它使用以下代码:
private readonly AuthenticationServiceClient service = new AuthenticationServiceClient();
public void SignIn(string userName, string password, bool createPersistentCookie)
using (new OperationContextScope(service.InnerChannel))
// login
service.Login(userName, password, String.Empty, createPersistentCookie);
// Get the response header
var responseMessageProperty = (HttpResponseMessageProperty)
OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name];
string encryptedCookie = responseMessageProperty.Headers.Get("Set-Cookie");
// parse header to cookie object
var cookieJar = new CookieContainer();
cookieJar.SetCookies(new Uri("http://localhost:1062/"), encryptedCookie);
Cookie cookie = cookieJar.GetCookies(new Uri("http://localhost:1062/"))[0];
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
if (null != ticket)
//string[] roles = RoleManager.GetRolesFromString(ticket.UserData);
HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(ticket), null);
FormsAuthentication.SetAuthCookie(HttpContext.Current.User.Identity.Name, createPersistentCookie);
它完全符合您对问题的评论所描述的内容。
编辑
我在此处发布此代码的服务器端部分以供参考。
public class HttpResponseMessageInspector : BehaviorExtensionElement, IDispatchMessageInspector, IServiceBehavior
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
HttpRequestMessageProperty httpRequest = request.Properties[HttpRequestMessageProperty.Name]
as HttpRequestMessageProperty;
if (httpRequest != null)
string cookie = httpRequest.Headers[HttpRequestHeader.Cookie];
if (!string.IsNullOrEmpty(cookie))
FormsAuthentication.Decrypt(cookie);
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(cookie);
string[] roles = PrincipalHelper.GetUserRoles(authTicket);
var principal = new BreakpointPrincipal(new BreakpointIdentity(authTicket), roles);
HttpContext.Current.User = principal;
// can deny request here
return null;
【讨论】:
哇,我确实错过了一些技巧。让我看看它是如何工作的,我会回复你的。不管我真的很感激你的努力和兴趣:) 这在表面上看起来不错,但我遇到了同样的问题:System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed。我对此错误的假设是,由于它是 2 个不同的上下文(客户端应用程序和服务应用程序),解密/加密不兼容?你是如何设置它来工作的?再次感谢您的关注和努力:) Asp.net MVC 和 WCF Host 应用程序是否在同一台机器上运行?如果不是,您必须将两个 Web.config 设置为使用相同的机器密钥。请参阅 [msdn.microsoft.com/en-us/library/ms998288.aspx] 在我的设置中,MVC 和 WCF 服务主机都在我本地机器上的 Visual Studio WebServer 中运行。所以机器钥匙是一样的。编辑:您也可以尝试将此代码添加到 WCF Host Global.cs 文件中以显式发送 cookie 以排除更多的一件事:msdn.microsoft.com/en-us/library/bb398778%28v=VS.100%29.aspx 我现在确实让它们在同一个机器上运行,但我运行的是 IIS7 而不是 cassini,所以机器密钥应该已经相同。将查看链接。谢谢 这对我有用:string encryptedTicket = cookie.Replace(String.Format("0=", FormsAuthentication.FormsCookieName), String.Empty);【参考方案2】:这对我有用...首先设置主机的身份验证行为(这里通过代码显示,但也可以在配置中完成):
ServiceAuthorizationBehavior author = Description.Behaviors.Find<ServiceAuthorizationBehavior>();
author.ServiceAuthorizationManager = new FormCookieServiceAuthorizationManager();
author.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
author.ExternalAuthorizationPolicies = new List<IAuthorizationPolicy> new CustomAuthorizationPolicy() .AsReadOnly();
然后是辅助类
internal class FormCookieServiceAuthorizationManager : ServiceAuthorizationManager
public override bool CheckAccess(OperationContext operationContext)
ParseFormsCookie(operationContext.RequestContext.RequestMessage);
return base.CheckAccess(operationContext);
private static void ParseFormsCookie(Message message)
HttpRequestMessageProperty httpRequest = message.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
if (httpRequest == null) return;
string cookie = httpRequest.Headers[HttpRequestHeader.Cookie];
if (string.IsNullOrEmpty(cookie)) return;
string regexp = Regex.Escape(FormsAuthentication.FormsCookieName) + "=(?<val>[^;]+)";
var myMatch = Regex.Match(cookie, regexp);
if (!myMatch.Success) return;
string cookieVal = myMatch.Groups["val"].ToString();
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(cookieVal);
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(authTicket.Name), new string[0]);
internal class CustomAuthorizationPolicy : IAuthorizationPolicy
static readonly string _id = Guid.NewGuid().ToString();
public string Id
get return _id;
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
evaluationContext.Properties["Principal"] = Thread.CurrentPrincipal;
evaluationContext.Properties["Identities"] = new List<IIdentity> Thread.CurrentPrincipal.Identity ;
return true;
public ClaimSet Issuer
get return ClaimSet.System;
当设置了 AspNetCompatibility 时,FormCookieServiceAuthorizationManager
稍微简单一些:
internal class FormCookieServiceAuthorizationManager : ServiceAuthorizationManager
public override bool CheckAccess(OperationContext operationContext)
Thread.CurrentPrincipal = HttpContext.Current.User;
return base.CheckAccess(operationContext);
【讨论】:
以上是关于如何在 ASP.Net MVC 应用程序中使用来自 WCF 身份验证服务的身份验证 cookie的主要内容,如果未能解决你的问题,请参考以下文章