【发布时间】:2019-08-15 18:30:13
【问题描述】:
我有针对 API 并使用 Identity Server 进行身份验证的网络核心 Web 应用程序(也作为 Web 应用程序)。因为应用程序是基于 Web 服务器的,所以我在存储来自 Identity Server 的访问令牌时遇到问题,应用程序在每个请求(在 Header 中)都需要该令牌以便与 API 通信。一个理想的流程是:用户启动应用程序并被提示输入他的电话号码(以获取 OTP 代码并进行身份验证),当提交电话号码时,一些外部提供商的身份服务器向用户发送 OTP 代码,现在用户被提示输入一次性密码。成功提交 OTP 代码后,Identity Server 对其进行验证并将访问令牌提供给客户端。这就是问题开始的地方。
首先,我尝试使用单例存储访问令牌,在 otp 验证存储(在某些字典中)与电话号码相关的访问令牌作为密钥之后。但是,问题是因为应用程序是基于网络服务器的,并且在服务器上的生产中,并不强制每个用户都必须在服务器上运行他的应用程序实例,所以单例是无用的,因为我们很可能在示例 3-4 中为 20 个用户运行应用程序并且在这种情况下,不止一个用户使用相同的单例! 然后我用谷歌搜索,发现最好的选择是在浏览器会话或文档 cookie 中存储访问令牌或该令牌的一些实际密钥。所以现在应用程序的工作方式是在 OTP 代码验证用户的电话号码和访问令牌存储在 Dictionary 集合中之后(现在更多的用户使用相同的集合,因为单例对此没有用),其中键是电话号码,访问令牌是值,然后是 javascript在 cookie 中触发并设置用户电话号码(在每个请求中),现在在创建 Bearer 标头时,我只需从当前请求中读取 cookie,并使用该电话号码从集合中获取访问令牌。 所以这个解决方案非常糟糕,因为您需要获取访问令牌的所有内容(登录后)都是修改 cookie 中的电话号码,如果您幸运并匹配集合中的一些现有号码,您将获得访问令牌并轻松访问 API .
下面是在每个请求中调用的方法,以便从集合中获取访问令牌,其中在 otp 验证后放置了带有电话号码的访问令牌。
public async Task<string> GetAccessToken()
{
string phoneNumber = GetUserPhoneNumber();
if (string.IsNullOrEmpty(phoneNumber))
throw new ArgumentNullException(nameof(phoneNumber));
if (_usersTokenStore == null || _usersTokenStore.Count == 0)
throw new NotImplementedException(nameof(_usersTokenStore));
var refSingleUser = new SingleUserTokenStore();
bool userHaveAccessToken = _usersTokenStore.TryGetValue(phoneNumber, out refSingleUser);
if (!userHaveAccessToken)
throw new Exception($"User with {phoneNumber} not authorized.");
if (refSingleUser.IsTimeToRefreshToken)
return await RefreshAndGetAccessToken();
return refSingleUser.AccessToken;
}
private string GetUserPhoneNumber()
{
if (_httpContext == null)
throw new ArgumentException(nameof(_httpContext));
var phoneNumberCookie = _httpContext.HttpContext.Request.Cookies.Where(c => c.Key == "phone_number").FirstOrDefault();
if (phoneNumberCookie.Value == null || phoneNumberCookie.Key == null)
return null;
return phoneNumberCookie.Value;
}
【问题讨论】:
标签: c# .net asp.net-core identityserver4