0

我正努力尝试从Xamarin Forms Android应用访问存储的api(这是默认的web api,带有值控制器等)。我发现了大量关于如何实现这一点的文档,但我不想使用“传统方式”,例如处理AuthenticationContext \ Authentication Result。该请求是在应用程序,而不是由微软,谷歌提供了一个等访问xamarin访问Azure存储的web api android

使用自定义登录表单我的登录工作是这样的:

HttpClient client = new HttpClient(); 
    var tokenEndpoint = "https://login.microsoftonline.com/testdir.onmicrosoft.com/oauth2/token"; 
    var body = "resource=www.graph.microsoft.com&client_id=" + App.ClientId + "&grant_type=password&username=" + UsernameEntry.Text + "&password=" + PasswordEntry.Text + ""; 
    var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded"); 
    var result = await client.PostAsync(tokenEndpoint, stringContent).ContinueWith<string>(response => response.Result.Content.ReadAsStringAsync().Result); 
    var jobject = JObject.Parse(result); 
    App.AccessToken = jobject["access_token"].Value<string>(); 

这就像一个魅力。我现在有了访问令牌,我可以使用它来从Azure AD中检索用户或任何内容。

我想要的东西类似于从web api中检索数据。我希望登录发生在幕后,而不是通过提供Microsoft登录表单并提示用户登录。

我想是这样的:

tokenEndpoint = "https://login.microsoftonline.com/testdir.onmicrosoft.com/oauth2/authorize"; 
    body = "client_id=xxxx&response_type=code&redirect_uri=https://testapi.azurewebsites.net/"; 
    result = await client.PostAsync(tokenEndpoint, stringContent).ContinueWith<string>(response => response.Result.Content.ReadAsStringAsync().Result); 
    jobject = JObject.Parse(result); 

但我总是得到一个错误,指出用户必须登录。 (我认为它基本上会尝试生成一个Microsoft登录表单,并且在尝试成功之后,它将直接访问api所需的授权代码)。

如果我可以从一次调用中检索授权码,然后用它来查询Web API,那将是非常棒的。

这里是我发现的,说明类似问题\情景一些有用的问题,但我没能包住所有信息成片的工作代码:

​​

Use OAuth2 for authentication against Azure AD to call WebAPI

Unable to use bearer token to access AAD-secure Web API

任何帮助将非常感谢。谢谢!

回答

0

这花了很长时间,但我终于得到它的工作。我使用了与登录部分几乎相同的方法,但使用了一个转义(查看工作登录机制的代码示例,请参阅问题的第一部分)。 使用下面的代码片段,我能够获得一个令牌,然后用它来访问我的自定义API:

var clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; 
var client_secret = "yyyy"; 
HttpClient client = new HttpClient(); 
string tokenEndpoint = "https://login.microsoftonline.com/testTenant.onmicrosoft.com/oauth2/token"; 
var body = "resource=" + clientId + "&client_id=" + clientId + "&client_secret=" + client_secret + "&grant_type=password&username=" + username + "&password=" + password + ""; 
var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded"); 
var result = await client.PostAsync(tokenEndpoint, stringContent).ContinueWith<string>(response => response.Result.Content.ReadAsStringAsync().Result); 
     JObject jobject = JObject.Parse(result); 
var accessToken = jobject["access_token"].Value<string>(); 

最棘手的部分是找出这些参数“资源”和“的client_id”必须具有相同的值,如Azure注册的自定义web api的App ID。在我做出允许代码工作的更改之前,我收到以下错误:

1)在名为testTenant.onmicrosoft.com的租户中未找到名为https://customApi.azurewebsites.net/的应用程序。如果应用程序尚未由租户的管理员安装或由租户中的任何用户同意,则可能会发生这种情况。您可能已将验证请求发送给错误的承租人。

这里的问题是我使用“https://customApi.azurewebsites.net/”作为资源。

2)应用程序'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'正在为自己请求一个令牌。仅当使用基于GUID的应用程序标识符指定资源时才支持此场景。

第一次出错后,我试着将资源替换为“https://testTenant.onmicrosoft.com/CustomApi”。看到错误消息,我用我的API的APP ID替换了链接。那就是诀窍。

虽然您生成了有效的密钥,但您也可能会遇到错误,指出client_secret无效。我不得不重新生成几次密钥,然后才能正常工作。

我还在MSDN上发布了关于此问题的线索。你可以在那里找到有用的资源。

请注意,这不是推荐的方法,并存在严重的安全风险。但在适用情况下可能会出现极少数情况:

“可能有些时候密码授予机制可以”可接受“ - 例如在仅供内部用户使用的核准公司计算机上安装的非公开应用程序中。那正是我的场景。

肖恩提供了宝贵的文档,包括如何做到这一点以及推荐的做法。

0

您在寻找Resource Owner Password Credentials Grant的。

有关于此流程的基本文档here

您应该知道,一般来说,Azure Active Directory团队强烈建议不要使用此流程,因为它需要您的应用程序处理用户的用户名和密码,这会带来许多安全问题。

请在这里阅读更多关于为什么你不应该这样做的警告。

Vittorio Bertocci - Using ADAL .NET to Authenticate Users via Username/Password

Rich Randall - How to authenticate user with Azure Active Directory using OAuth 2.0?

OAuth 2.0 Specification - Security Considerations

总结:我已经向您展示您如何做到这一点...但你不应该这样做。

+0

谢谢肖恩。我已经使用文章中描述的机制来制作自定义登录表单。我努力从自定义web api中检索数据,这些数据也是以azure托管的。我不知道如何检索所谓的“authorization_code”,并将其用于对自定义api的http请求中。我知道我的方法不被推荐,但我们的客户希望这种方法,因为实施的应用程序将用于安全的内部网络,应用程序将只在它们之间进行通信。 –

+1

对不起,我不太了解你目前的问题。你不知道如何获得授权码,然后获得访问令牌?授权码不能直接用于调用API。它必须交换为访问令牌。你是否能够获得访问令牌? –

+0

我能够从Microsoft图表获取访问令牌并使用它登录到Azure AD。现在我想使用类似的机制来访问我实现的自定义Web API。如果我理解正确,则建议使用与登录场景('https:// login.microsoftonline.com/testdir.onmicrosoft.com/oauth2/token')相同的端点调用,但使用作为资源的自定义web api我创建的,而不是微软的图形,这将提供一个令牌,我可以用它来访问我的API?我不知道如何交换授权码的访问令牌。 –