在Xamarin表单中使用oidc客户端来刷新您的访问令牌

显示有回收标志的图象智能手机在它

因此,您决定使用Openididity Connect / OAuth来验证您的Xamarin应用程序中的用户。伟大的事情是您的客户端应用程序永远不会看到或处理用户名和密码,这减少了可能的攻击向量。相反,您的所有应用程序都收到了一个访问令牌,可以授予需要经过身份验证的用户的API。但是有一个小警告。访问令牌通常仅在短时间内有效。使用IdentityServer,默认值为60分钟。理论上,这意味着您的用户必须进行身份验证 - 读取输入用户名和密码 - 每小时。这严重愈合,肯定必须是更好的方式。有。该应用程序可以代表用户在用户的刷新令牌上续订访问令牌,而无需任何必需的交互。

背部

我涵盖了如何整合 OIDC客户端 进入Xamarin表格在前者中的应用程序 邮政. As described, when the user authenticates him- or herself, we pass along the scopes we require. If we add the offline_access scope to the request and the server allows the scope request, we will receive a refresh token. You can configure on the IdentityServer how long a refresh token is valid and if it is enabled.

AllowOfflineAccess = true, // allow refresh tokens
AbsoluteRefreshTokenLifetime = 2592000, // in seconds ~> 30 days

With the above configuration, the LoginResult will contain a valid refresh token. Which is cool, but what now? When and how do we use this token? Let’s first look at when we want to use the refresh token. The client (in our case, the Xamarin Forms app) knows precisely when the access token is about to expire with the AccessTokenExpiration property on the LoginResult. So we could check before every request if the token is still valid. Perhaps subtract a few seconds to be on the safe side.

if(_loginResult.AccessTokenExpiration.ToUniversalTime().AddSeconds(-30) > DateTime.UtcNow)
{
    await _oidcIdentityService.Refresh(_loginResult.RefreshToken)
}

另一种选择是让后端告诉我们我们不再具有有效的访问令牌。我们可以通过调用API来执行此操作,如果呼叫返回a 401回应 - 我们知道访问令牌已过期,我们需要可能想要刷新令牌。

var response = await _httpClient.GetAsync(url);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
    if (string.IsNullOrEmpty(_loginResult?.RefreshToken))
    {
        // no valid refresh token exists => authenticate
        // ...
    }
    else
    {
        // we have a valid refresh token => refresh tokens
        // ...
    }
}

还有另外400个代码通常与身份验证相关 - 403。虽然401表示访问令牌无效。 403意味着用户没有正确的访问资源的许可。因此,如果非管理员用户希望访问某些管理功能,则预计将响应403响应。

这两种方法都有工作,由您更喜欢哪一个。当时间来刷新令牌时,我们可以要求一组新的令牌。

要求刷新

默认情况下,我们只能使用刷新令牌一次才能请求新的访问令牌。幸运的是,刷新结果不仅包含新的访问令牌,还包含一个新的刷新令牌。所以我们应该再次提出一组新的令牌。 OIDC客户端提供了一种为给定刷新令牌询问新的令牌的方法:

OidcClient oidcClient = CreateOidcClient();
RefreshTokenResult refreshTokenResult = await oidcClient.RefreshTokenAsync(refreshToken);

It returns a RefreshTokenResult, which contains kind of the same information as the LoginResult. But, unfortunately, they do not share their same properties in a base class, so that I would recommend to you create your Credentials class to store the information of the tokens:

public class Credentials
{
    public string AccessToken { get; set; } = "";
    public string IdentityToken { get; set; } = "";
    public string RefreshToken { get; set; } = "";
    public DateTime AccessTokenExpiration { get; set; }
    public string Error { get; set; } = "";
    public bool IsError => !string.IsNullOrEmpty(Error);
}

通过编写以下扩展方法:

public static Credentials ToCredentials(this LoginResult loginResult)
    => new Credentials
    {
        AccessToken = loginResult.AccessToken,
        IdentityToken = loginResult.IdentityToken,
        RefreshToken = loginResult.RefreshToken,
        AccessTokenExpiration = loginResult.AccessTokenExpiration
    };

public static Credentials ToCredentials(this RefreshTokenResult refreshTokenResult)
    => new Credentials
    {
        AccessToken = refreshTokenResult.AccessToken,
        IdentityToken = refreshTokenResult.IdentityToken,
        RefreshToken = refreshTokenResult.RefreshToken,
        AccessTokenExpiration = refreshTokenResult.AccessTokenExpiration
    };

然后,您可以将结果转换为您自己的凭据模型,这将使​​在应用程序中稍后更轻松地处理此信息。

RefreshTokenResult refreshTokenResult = await oidcClient.RefreshTokenAsync(refreshToken);
return refreshTokenResult.ToCredentials();

请注意,刷新可能会失败。通常是刷新令牌已经过期的主要原因。不幸的是,在这种情况下,在这种情况下没有办法,您必须使用您的漂亮登录对话框向用户展示。 ðÿ〜‰

除了访问令牌之外,服务器将存储每个客户端的刷新令牌。这也允许在服务器上撤消刷新令牌。由于每个客户端都有一个刷新令牌,因此一些网站将显示哪些客户/应用程序可以访问您的帐户。通过撤销许可证,删除刷新令牌,强制客户端重新修复(通过登录表格)。

存储令牌

使用刷新令牌,您可以创建仅需要用户一次(或至少少次)的应用程序,因为用户使用该应用程序时可以在后台自动续订访问令牌。此外,刷新令牌不包含任何信息。然而,如果有效的请求令牌落入错误的手中,潜在的攻击者可能会冒充用户。

所以不要把令牌和刷新令牌存放在本地存储中的某个地方,但使用 Xamarin Essentials安全存储。这将确保您将令牌保留在设备上可用的最安全位置。一旦您需要它们,您可以阅读它们,验证是否是续订令牌的时间,如果是的话。然后,为新批次发送HTTP请求。

后果

这就是您如何使用OAuth刷新令牌来请求新令牌,而无需提示您的用户遍及身份验证表单。请注意,必须在服务器上启用该功能,也是可以确定刷新令牌有效的长度有效的服务器。

强烈建议使用刷新令牌编写移动应用程序,因为它允许使用稳固和安全的身份验证机制,同时为用户提供愉快的体验。

您可以找到代码示例 这里 on GitHub.

Hth.

titlephoto by. 准备好了pexels.

Updated: