may*_*lle 12 authentication oauth oauth-2.0 asp.net-web-api owin
我正在尝试创建一个Web API,允许API的客户端(本机移动应用程序)使用第三方云存储提供程序登录.我正在使用Microsoft的以下一般流程:

这是我想要实现的目标:

我使用带有外部身份验证的默认ASP.NET Web API Visual Studio模板,以及用于Dropbox登录功能的OWin.Security.Providers Nuget包,以及用于Google(Drive)和Microsoft(OneDrive)的现有内置登录功能.
我遇到的问题是,内置功能似乎都是作为一个流程的一部分进行身份验证和授权.例如,如果我在Startup.Auth.cs中设置以下内容:
DropboxAuthenticationOptions dropboxAuthOptions = new DropboxAuthenticationOptions
{
AppKey = _dropboxAppKey,
AppSecret = _dropboxAppSecret
};
app.UseDropboxAuthentication(dropboxAuthOptions);
Run Code Online (Sandbox Code Playgroud)
...并从我的网络浏览器导航到此网址:
http://<api_base_url>/api/Account/ExternalLogin?provider=Dropbox&response_type=token&client_id=self&redirect_uri=<api_base_url>
Run Code Online (Sandbox Code Playgroud)
我已成功重定向到Dropbox登录:
https://www.dropbox.com/1/oauth2/authorize?response_type=code&client_id=<id>&redirect_uri=<redirect_uri>
Run Code Online (Sandbox Code Playgroud)
...然后在我授予访问权限后,重定向回到:
http://<api_base_url>/Help#access_token=<access_token>&token_type=bearer&expires_in=1209600
Run Code Online (Sandbox Code Playgroud)
...因为你可以看到令牌是其中的一部分,所以可以提取.问题是客户端需要导航到Dropbox并将授权代码返回到Web API,Web API会将授权代码发送回第三方以获取令牌,然后将其返回给客户......如上图所示.我需要AccountController中的ExternalLogin操作以某种方式检索Dropbox url并将其返回给客户端(它只是一个json响应),但我没有看到一种方法来检索它(它只返回一个ChallengeResult,并且实际的Dropbox网址埋在某处).此外,我认为我需要一种方法来根据授权代码单独请求来自第三方的令牌.
这篇文章似乎与我想要做的有点类似:
使用OWIN标识从多个API客户端注册Web API 2外部登录
...但是那里的解决方案似乎要求客户端成为MVC应用程序,对我来说不一定是这样.我希望在客户端保持尽可能简单,遵循上图中的流程,但也不要重新发明轮子(尽可能多地重用OWIN/OAuth2实现中已存在的内容).理想情况下,我不希望客户端必须引用任何OWIN/OAuth库,因为我真正需要客户端做的就是访问API提供的外部URL(在我的示例中为Dropbox),让用户输入他们的凭据并授予权限,并将生成的授权代码发送回api.
从概念上讲,这听起来并不难,但我不知道如何实现它,仍然尽可能多地使用现有的OAuth代码.请帮忙!
需要明确的是,我在您发布的链接中提到的示例可以与任何 OAuth2 客户端一起使用,使用任何支持的流程(隐式、代码或自定义)。当与您自己的授权服务器通信时,如果您想使用 JS 或移动应用程序,您当然可以使用隐式流程:您只需使用response_type=tokenJS 端的 URI 片段构建授权请求并提取访问令牌即可。
作为参考,这里是示例: https: //github.com/aspnet-security/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Mvc/Mvc.Server
如果您更喜欢更简单的方法(不涉及自定义 OAuth2 授权服务器),这里有另一个选项,使用 OAuth2 不记名身份验证中间件并实现自定义来手动IAuthenticationTokenProvider验证 Dropbox 颁发的不透明令牌。与提到的示例(充当 Dropbox 和 MVC 客户端应用程序之间的授权代理服务器)不同,JS 应用程序直接向 Dropbox 注册。
您必须使用收到的令牌向 Dropbox 配置文件端点 ( https://api.dropbox.com/1/account/info ) 发出请求,以对其进行验证并ClaimsIdentity为 API 收到的每个请求构建适当的实例。这是一个示例(但请不要按原样使用它,它尚未经过测试):
public sealed class DropboxAccessTokenProvider : AuthenticationTokenProvider {
public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context) {
using (var client = new HttpClient()) {
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.dropbox.com/1/account/info");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.Token);
var response = await client.SendAsync(request);
if (response.StatusCode != HttpStatusCode.OK) {
return;
}
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
var identity = new ClaimsIdentity("Dropbox");
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, payload.Value<string>("uid")));
context.SetTicket(new AuthenticationTicket(identity, new AuthenticationProperties()));
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以通过以下属性轻松插入它AccessTokenProvider:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions {
AccessTokenProvider = new DropboxAccessTokenProvider()
});
Run Code Online (Sandbox Code Playgroud)
它有其自身的缺点:它需要缓存以避免淹没 Dropbox 端点,并且如果您想接受不同提供商(例如 Dropbox、Microsoft、Google、Facebook)颁发的令牌,则不是正确的方法。
更不用说 if 提供了非常低的安全级别:由于您无法验证访问令牌的受众(即令牌颁发给的一方),因此您无法确保访问令牌已颁发给客户端应用程序您完全信任,这允许任何第三方开发人员将他自己的 Dropbox 令牌与您的 API 一起使用,而无需请求用户同意。
显然,这是一个主要的安全问题,这就是为什么您应该更喜欢链接示例中使用的方法。您可以在此线程上阅读有关混淆代理攻击的更多信息:/sf/answers/1220752221/。
祝您好运,如果您仍然需要帮助,请不要犹豫。
| 归档时间: |
|
| 查看次数: |
8376 次 |
| 最近记录: |