如何以测试代码中的用户身份登录Azure Active Directory?

时间:2019-02-12 13:11:04

标签: azure authentication oauth .net-core azure-active-directory

我是Azure的新手,在学习Azure Active Directory(AAD)的所有功能方面有些挣扎,所以希望您能为我解决一些问题。这是我已经做过的:

  • 我注册了一个网络应用程序,该应用程序充当资源提供者,并在API管理服务后面提供不同的API。

  • 该Web应用在AAD中具有多个用户和角色。另外,在应用程序级别上设置了更详细的权限。因此,AAD不能控制我用户的所有权限。

  • 使用 OAuth 2.0 对用户进行身份验证。实际上,这意味着如果新用户尝试登录到我的应用程序,他将被重定向到Microsoft的登录页面,输入用户名和密码,然后从Microsoft的身份验证服务器获取JWT令牌。

现在我想做什么:

我想编写一个在构建服务器上运行的应用程序,用于测试用户权限。该应用程序必须使用C#.NET Core编写。现在,我在为如何以用户身份登录我的代码而苦苦挣扎,所以我的问题是:

我如何以用户身份从代码登录到AAD并获取JWT令牌以测试用户权限?我可以仅使用用户名/密码来执行此操作,还是需要在AAD中注册测试应用程序?实现我的目标的最佳解决方案是什么?

提前谢谢

2 个答案:

答案 0 :(得分:2)

Juunas的评论已经涵盖了大部分要求。只是在后面加上一些细节。

  • 您可以使用MSAL(链接)来编写访问API的.NET Core应用程序。
  • 在MSAL内,您需要使用username password authentication (Resource Owner Password Credentials grant)来获取JWT令牌。请不要在测试应用程序之外使用此赠款。
  • 根据应用程序的配置方式,仅使用API​​的clientId就足够了。不过,最好的做法是注册一个单独的本地应用。

一些措辞可以帮助您:

  • ClientId:正在请求令牌的客户端应用程序的ID。
  • 范围:您为其获取令牌的API的范围。应该已经在您的API中的某个位置进行了配置。通常带有AppId URI的内容。可能的示例如下所示:
    • https://<yourtenant>.onmicrosoft.com/<yourapi>/user_impersonation
    • https://<clientId-of-API>/.default
    • ...
  • 权限:您的AAD,例如https://login.microsoftonline.com/yourtenant.onmicrosoft.com

来自Wiki的密码授予的代码示例(此处有更多示例):

static async Task GetATokenForGraph()
{
    string authority = "https://login.microsoftonline.com/contoso.com";
    string[] scopes = new string[] { "user.read" };
    PublicClientApplication app = new PublicClientApplication(clientId, authority);

        try
        {
            var securePassword = new SecureString();
            foreach (char c in "dummy")        // you should fetch the password
                securePassword.AppendChar(c);  // keystroke by keystroke

            result = await app.AcquireTokenByUsernamePasswordAsync(scopes, "joe@contoso.com",
                                                                   securePassword);
        }
        catch(MsalException)
        {
          // See details below
        }

    Console.WriteLine(result.Account.Username);
}

答案 1 :(得分:1)

实际上,我找到了一种无需使用MSAL库即可在“纯” C#中执行此操作的方法。因此,如果您正在寻找不使用MSAL的解决方案,则可以按照以下说明的方法进行。

先决条件

  • 用户必须存在于AAD中并且不能使用Microsoft帐户(Active Directory中的源不得为“ Microsoft帐户”)。
  • 必须在Azure Active Directory中注册客户端应用程序。必须向客户端应用程序授予您要测试的应用程序的权限。如果客户端应用程序的类型为“本机”,则无需提供任何客户端机密。如果客户端应用程序的类型为“ Web应用程序/ api”,则必须提供客户端密码。为了进行测试,建议使用没有客户端机密的“ Native”类型的应用。

  • 必须没有两个因素的验证。

C#代码

您可以创建一个“ JwtFetcher”类并使用如下代码:

    public JwtFetcher(string tenantId, string clientId, string resource)
    {
        this.tenantId = !string.IsNullOrEmpty(tenantId) ? tenantId : throw new ArgumentNullException(nameof(tenantId));
        this.clientId = !string.IsNullOrEmpty(clientId) ? clientId : throw new ArgumentNullException(nameof(clientId));
        this.resource = !string.IsNullOrEmpty(resource) ? resource : throw new ArgumentNullException(nameof(resource));
    }

    public async Task<string> GetAccessTokenAsync(string username, string password)
    {
        var requestContent = this.GetRequestContent(username, password);

        var client = new HttpClient
        {
            BaseAddress = new Uri(ApplicationConstant.Endpoint.BaseUrl)
        };

        var message = await client.PostAsync(this.tenantId + "/oauth2/token", requestContent).ConfigureAwait(false);

        message.EnsureSuccessStatusCode();

        var jsonResult = await message.Content.ReadAsStringAsync().ConfigureAwait(false);
        dynamic objectResult = JsonConvert.DeserializeObject(jsonResult);

        return objectResult.access_token.Value;
    }

    private FormUrlEncodedContent GetRequestContent(string username, string password)
    {
        List<KeyValuePair<string, string>> requestParameters = new List<KeyValuePair<string, string>>()
        {
            new KeyValuePair<string, string>(ApplicationConstant.RequestParameterName.GrantType, ApplicationConstant.RequestParameterValue.GrantTypePassword),
            new KeyValuePair<string, string>(ApplicationConstant.RequestParameterName.Username, username),
            new KeyValuePair<string, string>(ApplicationConstant.RequestParameterName.Password, password),
            new KeyValuePair<string, string>(ApplicationConstant.RequestParameterName.ClientId, this.clientId),
            new KeyValuePair<string, string>(ApplicationConstant.RequestParameterName.Resource, this.resource)
        };

        var httpContent = new FormUrlEncodedContent(requestParameters);
        return httpContent;
    }

为此授予的类型只是“密码”。