在ASP.NET Web API中同时使用基本身份验证和表单身份验证

13

免责声明:首先我要说我是新手,对MVC4 + Web Api + Web Services(总体上) + JQuery不熟悉。我可能从错误的角度进行攻击。

我正在尝试构建一个C#的Web MVC应用程序+Web API,以便部署到Azure。移动客户端(iOS,使用RestKit)将使用Web API。

Web MVC应用程序相对简单。我们希望为其使用Forms身份验证和SimpleMembership - 我们已经实现并且运行良好。

我们将使用JQuery(Knockout)脚本从Web API方法中提取页面的一部分。因此,我们期望JQuery使用由Forms身份验证进行身份验证的同一身份验证身份。

然而,问题在于,Web Api可以直接被移动客户端调用。这些请求不需要Forms身份验证。

我们一直在研究Thinktecture Identity Model (http://nuget.org/packages/Thinktecture.IdentityModelhttps://github.com/thinktecture/Thinktecture.IdentityModel.40)。我们向配置文件中添加了BasicAuth和AccessKey处理程序,并且它能够工作(请参见下面的代码)。

当您未经身份验证尝试访问Web Api时,浏览器会显示基本身份验证对话框,它可以按预期工作。

“问题”在于,当您已经通过Forms身份验证登录并尝试调用Web Api方法时,仍会出现基本身份验证对话框。换句话说,Thinktecture IdentityModel似乎完全忽略了Forms身份验证。

我的问题是:

  1. 我的期望是正确的吗?一旦我完成了forms身份验证,是否不需要进行其他任何操作即可让JQuery脚本等从同一浏览器用户会话中访问Web API。
  2. 如何解决这个问题?
  3. 如果我的期望不正确,则应该如何处理?也就是说:我如何使JQuery脚本进行身份验证?

我知道Stackoverflow上有大量类似的问题,我真的查找了很多,并看了视频等,但要么我漏掉了一些明显的地方,要么对于新手来说没有清晰的文档。

感谢帮助。谢谢。

public static AuthenticationConfiguration CreateConfiguration()
{
var config = new AuthenticationConfiguration
        {
            DefaultAuthenticationScheme = "Basic",
            EnableSessionToken = true,
            SetNoRedirectMarker = true
        };            

config.AddBasicAuthentication((userName, password) => userName == password, retainPassword: false);
config.AddAccessKey(token =>
        {
            if (ObfuscatingComparer.IsEqual(token, "accesskey123"))
            {
                return Principal.Create("Custom",
                    new Claim("customerid", "123"),
                    new Claim("email", "foo@customer.com"));
            }

            return null;
        }, AuthenticationOptions.ForQueryString("key"));
1个回答

6

我之前提出了解决此问题的方案。

注意:此解决方案不涉及Thinktecture Identity Model。

我有一个抽象的BasicAuthenticationHandler类,它是一个委托处理程序。您可以通过安装最新稳定版WebAPIDoodle NuGet包来获取此处理程序。

如果请求已经进行过身份验证(例如:通过表单auth),则可以给此基本身份验证处理程序一个提示来抑制身份验证过程。您需要注册的自定义处理程序将如下所示:

public class MyApplicationAuthHandler : BasicAuthenticationHandler {

    public MyApplicationAuthHandler() 
        : base(suppressIfAlreadyAuthenticated: true) { }

    protected override IPrincipal AuthenticateUser(
        HttpRequestMessage request, 
        string username, 
        string password, 
        CancellationToken cancellationToken) { 

        //this method will be called only if the request
        //is not authanticated.

        //If you are using forms auth, this won't be called
        //as you will be authed by the forms auth bofore you hit here
        //and Thread.CurrentPrincipal would be populated.

        //If you aren't authed:
        //Do you auth here and send back an IPrincipal 
        //instance as I do below.

        var membershipService = (IMembershipService)request
            .GetDependencyScope()
            .GetService(typeof(IMembershipService));

        var validUserCtx = membershipService
            .ValidateUser(username, password);

        return validUserCtx.Principal;
    }

    protected override void HandleUnauthenticatedRequest(UnauthenticatedRequestContext context) {

        // Do nothing here. The Autharization 
        // will be handled by the AuthorizeAttribute.
    }
}

作为最后一步,您需要将System.Web.Http.AuthorizeAttribute(而不是System.Web.Mvc.AuthorizeAttribute)应用于您的控制器和操作方法,以授权特定角色和用户。
希望这可以帮助解决您的问题。

你好,这很不错。但是,“IMembershipService”接口从哪里来?(它似乎不是WebAPIDoongle或标准的.NET4 MVC的一部分)。请注意,您的类可以工作,我希望同样的类也可以处理API密钥,但是我相信我可以添加该功能。我现在的主要问题是如何使用“WebSecurity”类对用户进行验证并根据数据库返回Principal(我可以执行WebSecurity.Login,但那很俗气)。 - rufo
顺便说一句:当从浏览器(Chrome)进行测试时,如果用户未登录,则不会强制浏览器提供基本身份验证。虽然这对我的移动客户端来说并非必要,但对于测试来说很方便。我也会检查一下。 - rufo
@rufo IMembershipService是我自己的实现。我把它放在那里让你了解一下。你可以用自己的实现来替换它。 - tugberk
@rufo 这里是ApiKeyAuthenticationHandler。由于源代码对于两者都是可用的,你可以混合它们并创建自己的代码。 - tugberk
1
@rufo 如果你想要这种行为,就将[HandleUnauthenticatedRequest](https://github.com/WebAPIDoodle/WebAPIDoodle/blob/dev/src/apps/WebAPIDoodle/Http/Handlers/BasicAuthenticationHandler.cs#L118)方法保留为原样。就像我的示例中所示,我用自己的行为替换了它,什么都不做,并将授权留给AuthorizeAttribute。 - tugberk
非常感谢。我相信这已经启动了我。 - rufo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接