【发布时间】:2016-07-20 21:01:50
【问题描述】:
我正在使用 oauth 令牌访问 web api。
令牌在1 hour 之后过期。但我想添加功能以在到期时生成新令牌。
我发现如果令牌过期,它会将 StatusCode 发送为unauthorized。
请让我知道它是否是唯一告诉我令牌过期的状态码。
【问题讨论】:
标签: c# asp.net-web-api oauth
我正在使用 oauth 令牌访问 web api。
令牌在1 hour 之后过期。但我想添加功能以在到期时生成新令牌。
我发现如果令牌过期,它会将 StatusCode 发送为unauthorized。
请让我知道它是否是唯一告诉我令牌过期的状态码。
【问题讨论】:
标签: c# asp.net-web-api oauth
最简单的方法是尝试使用它调用服务。如果它过期了,它会拒绝它,然后你可以请求一个新的。
您还可以保留收到令牌的时间,并使用expires_in 计算它大约何时到期。然后在到期日期之后发出新请求之前请求新令牌。
【讨论】:
HTTP 401, Unauthorized。
403 应该告诉您您已通过身份验证,但您不允许您请求的资源。 401 只是告诉你你的令牌是错误的,过期/错误/无效/坏。身份验证没有ALMOST 状态。
我知道这是一个旧帖子,但有更直接的方法。如果您从 Base64 格式解码令牌,您可以看到到期日期是什么,然后您可以将其与现在的日期进行比较。
如果您想检查此方法是否有效,您可以使用this website 来解码令牌。
现在,在 C# 中,您遇到了一些困难,因为标记包含 '.'无法解码,如果您只取出两点之间的中间部分,则长度将变为无效(它应该始终是 4 的倍数)。要使中间部分具有正确的长度,您可以添加“=”符号,直到它是 4 的倍数。
最后,我将日期与当前日期加一分钟进行比较。因为我不希望将在一秒钟内过期的令牌被视为有效。您可能需要调整该时间以适合您的目的。
这是我的代码:
/***
* Check if the string token is expired by decoding it from the Base64 string
* Some adjustements to the string are necessairy since C# can only decode certain strings.
* It cannot handle '.' and requires a string has a length that is a multitude of 4.
* The information we are interrested in is found between the dots.
*
* The token that is given as a parameter should have approximately the following structure:
* ddddddddddddddddddddd.ddddddddddddddddddddddddddddddddddddd.dddddddddddddddddddddddddddd
* And should be a valid Oauth token that may or may not be expired
*/
public static bool isExpired(String token)
{
if (token == null || ("").Equals(token))
{
return true;
}
/***
* Make string valid for FromBase64String
* FromBase64String cannot accept '.' characters and only accepts stringth whose length is a multitude of 4
* If the string doesn't have the correct length trailing padding '=' characters should be added.
*/
int indexOfFirstPoint = token.IndexOf('.') + 1;
String toDecode = token.Substring(indexOfFirstPoint, token.LastIndexOf('.') - indexOfFirstPoint);
while (toDecode.Length % 4 != 0)
{
toDecode += '=';
}
//Decode the string
string decodedString = Encoding.ASCII.GetString(Convert.FromBase64String(toDecode));
//Get the "exp" part of the string
String beginning = "\"exp\":\"";
int startPosition = decodedString.LastIndexOf(beginning) + beginning.Length;
decodedString = decodedString.Substring(startPosition);
int endPosition = decodedString.IndexOf("\"");
decodedString = decodedString.Substring(0, endPosition);
long timestamp = Convert.ToInt64(decodedString);
DateTime date = new DateTime(1970, 1, 1).AddMilliseconds(timestamp);
DateTime compareTo = DateTime.Now.AddMinutes(1);
int result = DateTime.Compare(date, compareTo);
return result < 0;
}
【讨论】:
再次复活这篇文章并采用@Lavandysh 的解决方案并加入System.IdentityModel.Tokens.Jwt 课程;调用此方法以了解令牌在请求之前是否仍然有效:
public bool _isEmptyOrInvalid (string token)
{
if (string.IsNullOrEmpty(token))
{
return true;
}
var jwtToken = new JwtSecurityToken(token);
return (jwtToken == null) || (jwtToken.ValidFrom > DateTime.UtcNow) || (jwtToken.ValidTo < DateTime.UtcNow);
}
【讨论】:
我在开发 Xamarin Forms 应用程序时遇到了这个问题。这里的主要问题是我无法在项目中安装任何 Nuget。所以我决定改进@Lavandysg 的答案,因为它没有正确提取到期时间戳,也没有正确计算到期时间。这是我使用正则表达式从令牌中提取过期时间的最终代码:
public bool IsTokenExpired(string token)
{
if (token == null || ("").Equals(token))
{
return true;
}
/***
* Make string valid for FromBase64String
* FromBase64String cannot accept '.' characters and only accepts stringth whose length is a multitude of 4
* If the string doesn't have the correct length trailing padding '=' characters should be added.
*/
int indexOfFirstPoint = token.IndexOf('.') + 1;
String toDecode = token.Substring(indexOfFirstPoint, token.LastIndexOf('.') - indexOfFirstPoint);
while (toDecode.Length % 4 != 0)
{
toDecode += '=';
}
//Decode the string
string decodedString = Encoding.ASCII.GetString(Convert.FromBase64String(toDecode));
//Get the "exp" part of the string
Regex regex = new Regex("(\"exp\":)([0-9]{1,})");
Match match = regex.Match(decodedString);
long timestamp = Convert.ToInt64(match.Groups[2].Value);
DateTime date = new DateTime(1970, 1, 1).AddSeconds(timestamp);
DateTime compareTo = DateTime.UtcNow;
int result = DateTime.Compare(date, compareTo);
return result < 0;
}
【讨论】: