2011-04-12 67 views
24

我正在尝试编写一个ASP.NET MVC应用程序,该应用程序是我们拥有SOAP Web服务的CRM的前端。我希望用户使用他们的CRM用户名和密码登录我的Web应用程序,然后通过CRM进行身份验证,在页面上进行Web服务调用等。ASP.NET MVC Forms对外部Web服务的身份验证

我开始使用Forms身份验证并实现自定义成员资格提供者 - 我可以实现所需的所有方法,例如ValidateUser(),但是我遇到的问题是,登录到CRM Web服务后,您将获得一个令牌,并且必须随每次后续Web服务调用都传递该令牌,而我不知道我可以在哪里存储这个。

所以我的问题是:

  • 是窗体身份验证去这里的路呢,还是要更直接地处理所有的认证自己和存储在会话令牌。
  • 如果表单身份验证是要走的路,我应该在哪里以及如何存储这样的附加信息。它似乎喜欢使用表单身份验证,但随后将额外的信息(与身份验证相关)加载到cookie之外或者会话之外会有点混乱?

任何意见,将不胜感激

回答

36

您可以将认证令牌存储在窗体身份验证cookie的用户数据的一部分。这样它就可以在每个请求中使用。

因此,例如,一旦你验证用户的凭据可以查询Web服务,以获得令牌和手动创建并放出窗体身份验证Cookie:

[HttpPost] 
public ActionResult LogOn(string username, string password) 
{ 
    // TODO: verify username/password, obtain token, ... 
    // and if everything is OK generate the authentication cookie like this: 

    var authTicket = new FormsAuthenticationTicket(
     2, 
     username, 
     DateTime.Now, 
     DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes), 
     false, 
     "some token that will be used to access the web service and that you have fetched" 
    ); 
    var authCookie = new HttpCookie(
     FormsAuthentication.FormsCookieName, 
     FormsAuthentication.Encrypt(authTicket) 
    ) 
    { 
     HttpOnly = true 
    }; 
    Response.AppendCookie(authCookie); 

    // ... redirect 
} 

然后,你可以写一个自定义授权属性这将读取该信息并设置自定义通用的身份:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 
public class MyAuthorizeAttribute : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var isAuthenticated = base.AuthorizeCore(httpContext); 
     if (isAuthenticated) 
     { 
      string cookieName = FormsAuthentication.FormsCookieName; 
      if (!httpContext.User.Identity.IsAuthenticated || 
       httpContext.Request.Cookies == null || 
       httpContext.Request.Cookies[cookieName] == null) 
      { 
       return false; 
      } 

      var authCookie = httpContext.Request.Cookies[cookieName]; 
      var authTicket = FormsAuthentication.Decrypt(authCookie.Value); 

      // This is where you can read the userData part of the authentication 
      // cookie and fetch the token 
      string webServiceToken = authTicket.UserData; 

      IPrincipal userPrincipal = ... create some custom implementation 
              and store the web service token as property 

      // Inject the custom principal in the HttpContext 
      httpContext.User = userPrincipal; 
     } 
     return isAuthenticated; 
    } 
} 

最后装点你的控制器/需要与这个属性认证操作:

[MyAuthorize] 
public ActionResult Foo() 
{ 
    // HttpContext.User will represent the custom principal you created 
    // and it will contain the web service token that you could use to 
    // query the remote service 
    ... 
} 
+0

谢谢,这太棒了。我会去那里。 – 2011-04-12 09:46:44

+1

加上w/s令牌在表单票据中得到加密,所以不能被盗或读(理论上) – 2011-04-12 15:31:15

+0

好极了,但是我把“base.AuthorizeCore(httpContext);”到方法的末尾,就我们想要在角色检查之前设置主体而言。 – mikalai 2012-07-26 09:20:12