C#实现使用微软账户集成登录

版权声明

Microsoft account integrated sign in via C#” by Anduin Xue, used under CC AS 4.0, ‎translate from original.

本文翻译自 Anduin Xue 的 “Microsoft account integrated sign in via C#” ,依据 CC AS 4.0 协议授权。


下面的简单代码说明了如何构建一个支持使用 Microsoft 账户的 OAuth 身份认证。

在开始打代码之前,我们需要在你的 Azure portal 中先创建一个App。 https://portal.azure.com

azure portal

这个名字是你的App显示的名字。选中让你的应用可以访问任何组织账号和个人账号的那项。至于重定向URI,它必须是你的服务器重定向地址,比如:

1
https://gateway.aiursoft.com/debug

创建应用

创建完应用后,在这里复制你的 application id:

app id

然后创建一个 secret。

secret

别忘了复制那个 secret。

运行下面说的代码需要一些像 AiurUrlAiursoft.XelNaga.Services.HTTPService 这样的类。运行下面这行命令来获取:

1
$ dotnet add package Aiursoft.XelNaga

为了让用户登录,我们需要重定向到微软的登录门户。复制以下的代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public string GetBindRedirectLink()
{
    return new AiurUrl("https://login.microsoftonline.com", $"/{_tenant}/oauth2/v2.0/authorize", new MicrosoftAuthAddressModel
    {
        ClientId = _clientId,
        RedirectUri = "https://gateway.aiursoft.com/debug",
        ResponseType = "code",
        Scope = "user.read",
        State = ""
    }).ToString();
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class MicrosoftAuthAddressModel
{
    [FromQuery(Name = "client_id")]
    public string ClientId { get; set; }
    [FromQuery(Name = "redirect_uri")]
    public string RedirectUri { get; set; }
    [FromQuery(Name = "state")]
    public string State { get; set; }
    [FromQuery(Name = "scope")]
    public string Scope { get; set; }
    [FromQuery(Name = "response_type")]
    public string ResponseType { get; set; }
}

只需要返回给浏览器一个redirect result 和从 GetRedirectLink() 函数获取到的重定向链接。

用户成功的登录了他的账户的时候,将会带着一个码重定向回到你设置的 RedirectUri。这个码正式我们需要的。

通过这个码,你可以调用 GetUserDetail() 方法来获取用户的信息。

1
2
3
4
5
public async Task<IUserDetail> GetUserDetail(string code)
{
    var token = await GetAccessToken(_clientId, _clientSecret, code);
    return await GetUserInfo(token);
}

_clientId_clientSecret 是你创建这个 app 时候复制的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private async Task<string> GetAccessToken(string clientId, string clientSecret, string code)
{
    var apiAddress = "https://login.microsoftonline.com" + $"/{_tenant}/oauth2/v2.0/token";
    var url = new AiurUrl(apiAddress, new { });
    var form = new AiurUrl(string.Empty, new MicrosoftAccessTokenAddressModel
    {
        ClientId = clientId,
        ClientSecret = clientSecret,
        Code = code,
        Scope = "user.read",
        RedirectUri = "https://gateway.aiursoft.com/debug",
        GrantType = "authorization_code"
    });
    try
    {
        var json = await _http.Post(url, form, false);
        var response = JsonConvert.DeserializeObject<AccessTokenResponse>(json);
        if (string.IsNullOrWhiteSpace(response.AccessToken))
        {
            throw new AiurAPIModelException(ErrorType.Unauthorized, "Invalid Microsoft crenditial");
        }
        return response.AccessToken;
    }
    catch (WebException)
    {
        throw new AiurAPIModelException(ErrorType.Unauthorized, "Invalid Microsoft API response");
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public class MicrosoftAccessTokenAddressModel
{
    [FromQuery(Name = "client_id")]
    public string ClientId { get; set; }
    [FromQuery(Name = "client_secret")]
    public string ClientSecret { get; set; }
    [FromQuery(Name = "code")]
    public string Code { get; set; }
    [FromQuery(Name = "scope")]
    public string Scope { get; set; }
    [FromQuery(Name = "grant_type")]
    public string GrantType { get; set; }
    [FromQuery(Name = "redirect_uri")]
    public string RedirectUri { get; set; }
}

GetAccessToken() 方法能够帮助你获取一个有效的能够让你下载到用户信息的 access token。

你拿到了 access token 之后,只需要调用 GetUserInfo() 即可。下面我们将调用 graph API 来获取当前用户的信息。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
private async Task<MicrosoftUserDetail> GetUserInfo(string accessToken)
{
    var apiAddress = "https://graph.microsoft.com/v1.0/me";
    var request = new HttpRequestMessage(HttpMethod.Get, apiAddress);

    request.Headers.Add("Authorization", $"Bearer {accessToken}");
    var response = await _client.SendAsync(request);
    if (response.IsSuccessStatusCode)
    {
        var json = await response.Content.ReadAsStringAsync();
        var user = JsonConvert.DeserializeObject<MicrosoftUserDetail>(json);
        return user;
    }
    else
    {
        throw new WebException(response.ReasonPhrase);
    }
}

返回的用户是一个 MicrosoftUserDetail 的实例。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class MicrosoftUserDetail : IUserDetail
{
    [JsonProperty("id")]
    public string Id { get; set; }
    [JsonProperty("displayName")]
    public string DisplayName{ get; set; }
    [JsonProperty("userPrincipalName")]
    public string UserPrincipalName { get; set; }
    [JsonProperty("jobTitle")]
    public string JobTitle{ get; set; }
}

Id 是唯一的,可以使用这个来认证你的用户。

最后,构建一个个性化的网页,然后你的app就行力。

网页

源代码在这:

https://github.com/AiursoftWeb/Nexus/blob/master/Pylon/Services/Authentication/ToMicrosoftServer/MicrosoftService.cs

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License

冀ICP备17015375-1号
使用 Hugo 构建
主题 StackJimmy 设计