微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

OWIN / OAuth2第三方登录:来自客户端应用程序的认证,来自Web API的授权

我正在尝试创建一个允许API客户端(原生移动应用)使用第三方云存储提供商登录的Web API.我正在使用Microsoft的以下一般流程:

这是我要实现的目标:

我正在使用具有外部身份验证的认ASP.NET Web API Visual Studio模板,以及用于DropBox登录功能OWin.Security.Providers Nuget软件包以及Google(驱动器)和Microsoft(OneDrive)的现有内置登录功能.

我遇到的问题是内置的功能似乎都作为一个流程的一部分进行身份验证和授权.例如,如果我在Startup.Auth.cs中设置了以下内容

DropBoxAuthenticationoptions dropBoxAuthOptions = new DropBoxAuthenticationoptions
                                                    {
                                                        AppKey = _dropBoxAppKey,AppSecret = _dropBoxAppSecret
                                                    };
app.UseDropBoxAuthentication(dropBoxAuthOptions);

…并从我的网页浏览器导航到这个网址:

http://<api_base_url>/api/Account/ExternalLogin?provider=DropBox&response_type=token&client_id=self&redirect_uri=<api_base_url>

我已成功重定向到DropBox登录

https://www.dropBox.com/1/oauth2/authorize?response_type=code&client_id=<id>&redirect_uri=<redirect_uri>

…然后在我授予访问权限后,我重定向到:

http://<api_base_url>/Help#access_token=<access_token>&token_type=bearer&expires_in=1209600

…因为你可以看到令牌是其中的一部分,所以可以提取.问题是客户端需要一个导航到DropBox并将授权码返回到Web API,而Web API会将授权码发送回第三方,以获取令牌,然后将其返回给客户端…如上图所示.我需要在AccountController中的ExternalLogin操作以某种方式检索DropBox url并将其返回给客户端(它只是一个json响应),但是我没有看到一种方法来检索(它只返回一个ChallengeResult,而实际的DropBox网址被埋在某个地方).另外,我想我需要一种方法,根据授权码单独地向第三方请求令牌.

这个帖子似乎和我想要做的有点类似:

Registering Web API 2 external logins from multiple API clients with OWIN Identity

…但解决方案似乎要求客户端是一个MVC应用程序,这对我来说不一定.我想保持客户端尽可能的简单,按照上面的图表的流程,但也不能重新发明轮(尽可能多地重用OWIN / OAuth2实现中已经存在的内容).理想情况下,我不希望客户端引用任何OWIN / OAuth库,因为我真的需要客户端要做的就是访问API提供的外部URL(在我的示例中为DropBox),让用户输入他们的凭据并授予权限,并将得到的授权码发送回api.

从概念上讲,这听起来不是很难,但是我不知道如何实现它,并仍然尽可能使用现有的OAuth代码.请帮忙!

解决方法

要清楚,我在您发布的链接中提到的示例可以与任何OAuth2客户端一起使用,使用任何支持的流(隐式,代码自定义).当您与自己的授权服务器进行通信时,如果要使用JS或移动应用程序,您当然可以使用隐式流程:您只需使用response_type = token构建授权请求,并从JS中的URI片段中提取访问令牌侧.

http://localhost:55985/connect/authorize?client_id=myClient&redirect_uri=http%3a%2f%2flocalhost%3a56854%2f&response_type=token

作为参考,以下是示例: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)发出请求以对其进行验证,并为您的API收到的每个请求构建一个充足的ClaimIdentity实例.这是一个示例(但请不要按原样使用它,它还没有被测试):

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()));
        }
    }
}

您可以通过AccesstokenProvider属性轻松插入:

app.USEOAuthBearerAuthentication(new OAuthBearerAuthenticationoptions {
    AccesstokenProvider = new DropBoxAccesstokenProvider()
});

它有它自己的缺点:它需要缓存来避免淹没DropBox端点,如果你想接受由不同的提供者(例如DropBox,Microsoft,Google,Facebook)发出的令牌,那么它不是正确的方法.

更不用说提供非常低的安全级别:由于您无法验证访问令牌(即颁发令牌的方)的受众,您无法确保访问令牌已发布到客户端应用程序您完全信任,允许任何第三方开发人员使用自己的DropBox令牌与您的API,而无需请求用户的同意.

这显然是一个主要的安全问题,这就是为什么你应该更喜欢链接样本中使用的方法.你可以阅读更多关于这个线程的混乱的副攻击:https://stackoverflow.com/a/17439317/542757.

祝你好运,如果还需要帮助,不要犹豫.

原文地址:https://www.jb51.cc/html/229515.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐