5

我想使用 ASP.NET SimpleMembership 对使用我的 WebAPI 的用户进行身份验证。Thinktecture 有一个很棒的身份验证库,名为 Thinktecture.IdentityModel (http://thinktecture.github.com/Thinktecture.IdentityModel.45/),其中一个示例将 Forms Auth 与 Basic Auth ( source ) 联系起来。但是,该示例使用 Membership.ValidateUser() 如果没有 ASP.NET Membership 提供程序就无法工作,SimpleMembership (source)不支持(编辑:这不完全正确,请参阅下面的 Mark 回答)。


编辑

这是我所做的:

1) 创建一个新的 MVC Internet 应用程序

2) 通过 NuGet 安装 Thinktecture.IdentityModel

3)通过脚手架创建模型和api控制器:

public class Goober
{
    public int GooberId { get; set; }
    public string GooberWords { get; set; }
}

4)运行项目,创建一个新用户并使用 Fiddler 创建一个新 Goober

5) 为 GetGoober(int id) 添加 [Authorize]

6)在 WebApiConfig.cs 添加:

var authConfig = new AuthenticationConfiguration();

authConfig.AddBasicAuthentication((userName, password) =>
    Membership.ValidateUser(userName, password));

config.MessageHandlers.Add(new AuthenticationHandler(authConfig));

当我运行该项目并使用 Fiddler 访问 api/goober/1 时,我得到一个401 www-Authenticate: unspecified。但是,如果我首先使用 AccountController 登录,然后使用 Fiddler,我会得到200,一切都很好。

编辑

好的,我认为这个问题与我最初的问题无关。我怀疑它与模板中 SimpleMembership 的初始化有关。当我打开项目并运行调试然后使用 Fiddler 访问 api 时,我无法通过 Auth。但是,当我只需单击 Web 前端上的“注册”链接时,我就会通过 Auth。我猜这是因为在 AccountController 上调用了 InitializeSimpleMembershipAttribute,所以在调用控制器之前不会初始化?


我尝试使用 WebSecurity.Login() 代替 Membership.ValidateUser() 但这不起作用。

我不知道如何实际实现这一点。有人有建议吗?还是我试图从错误的角度解决这个问题?

4

1 回答 1

3

You are correct that ASP.NET Membership provider is not compatible with the SimpleMembershipProvider however SimpleMembershipProvider does support ValidateUser, see here. Assuming SimpleMembership is correctly configured and initalised you should still be able to call Membership.ValidateUser().

If you have already tried Membership.ValidateUser() and got an error please let me know and we can try resolve it.

Update

So having followed your reproduction steps I have managed to pin-point an error. Having brought the Thinktecture AuthenticationHandler handler inline and run in debug. 30 seconds after a request to the api controller a database connection error is being raised. This is failing asynchronously and silently.

After some fiddling around I believe it is the DefaultConnection connection string which is at fault.

Like me your default connection probably contains a file name like this: AttachDBFilename=|DataDirectory|\aspnet-MvcApplication3-20121215104323.mdf"

When ValidateUser is called inside the delegate registered at app start up (for validating the credentials) it appears to be failing to resolve |DataDirectory| I found that by updating this path to the full name my connection problems went away.

<connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-MvcApplication3-20121215104323;Integrated Security=SSPI;AttachDBFilename=C:\mydatabase\file\path\example\aspnet-MvcApplication-20121215104323.mdf" providerName="System.Data.SqlClient" />
</connectionStrings>

I then found this post here, it indicates that the AppDomain has not had it's data directory set correctly at this point.

So once the config set up and the connection string altered with a proper file path and a user name "test" and a password "testing" this request through fiddler got a 200:

GET http://localhost/api/goober/1
User-Agent: Fiddler
Host: localhost
Authorization: Basic dGVzdDp0ZXN0aW5n

As an aside

I found that to get the forms authorisation token to also allow access to the api controllers I had to add this. Otherwise the Thinkteckture code sets the principle back to anonymous:

Add this

authConfig.InheritHostClientIdentity = true;

To counteract this (line 52):

if (_authN.Configuration.InheritHostClientIdentity == false)
{
   //Tracing.Information(Area.HttpAuthentication, "Setting anonymous principal");
   SetPrincipal(Principal.Anonymous);
}
于 2012-12-15T11:19:13.650 回答