针对外部Web服务的ASP.NET MVC Forms身份验证

时间:2011-04-12 09:33:45

标签: c# asp.net asp.net-mvc web-services forms-authentication

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

我开始考虑使用表单身份验证和实现自定义成员资格提供程序 - 我可以实现我需要的所有方法ValidateUser(),但我遇到的问题是登录到CRM Web服务后给出一个必须与每个后续Web服务调用一起传递的令牌,我不知道我可以在哪里存储它。

所以我的问题是:

  • 是表单身份验证的方式,或者是自己处理所有身份验证并将令牌存储在Session中更直接。
  • 如果要进行表单身份验证,我应该在何处以及如何存储此类附加信息。似乎喜欢使用表单身份验证,但随后将一大堆额外信息(与身份验证相关)撞到一个cookie或会话之外会有点混乱?

任何建议都将不胜感激

1 个答案:

答案 0 :(得分:36)

您可以将身份验证令牌存储在窗体身份验证cookie的userData部分中。这样,每次请求都可以使用它。

因此,例如,一旦验证了用户的凭据,就可以查询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
    ...
}