我正在使用.NET Core 2.0在RESTful服务的客户端上工作。远程服务返回这样的挑战:
WwwAuthenticate: Bearer realm="https://somesite/auth",service="some site",scope="some scope"
需要转换为令牌请求,例如:
GET https://somesite/auth?service=some%20site&scope=some%20scope
使用AuthenticationHeaderValue
解析标题以获取方案和参数很简单,但这只是realm="https://somesite/auth",service="some site",scope="some scope"
字符串。如何轻松可靠地将其解析为单个realm
,service
和scope
组件?它不是JSON,所以使用NewtonSoft JsonConvert
反序列化它不会起作用。我可以将它改为看起来像XML或JSON的东西,但这看起来非常hacky(更不用说不可靠)。
肯定有更好的方法吗?
答案 0 :(得分:1)
因为我没有看到非黑客的方式。也许这种 hacky 方式可能有所帮助
string input = @"WwwAuthenticate: Bearer realm=""https://somesite/auth"",service=""some site"",scope=""some, scope""";
var dict = Regex.Matches(input, @"[\W]+(\w+)=""(.+?)""").Cast<Match>()
.ToDictionary(x => x.Groups[1].Value, x => x.Groups[2].Value);
var url = dict["realm"] + "?" + string.Join("&", dict.Where(x => x.Key != "realm").Select(x => x.Key + "=" + WebUtility.UrlEncode(x.Value)));
<强>输出强>
url => https://somesite/auth?service=some+site&scope=some%2C+scope
BTW:我在&#34;范围内添加了,
&#34;
答案 1 :(得分:0)
使用RFC6750和RFC2616中定义的架构,下面提供了一个更为精确的解析器实现。该解析器考虑了字符串可能包含=
,,
和/或转义的"
的可能性。
internal class AuthParamParser
{
private string _buffer;
private int _i;
private AuthParamParser(string param)
{
_buffer = param;
_i = 0;
}
public static Dictionary<string, string> Parse(string param)
{
var state = new AuthParamParser(param);
var result = new Dictionary<string, string>();
var token = state.ReadToken();
while (!string.IsNullOrEmpty(token))
{
if (!state.ReadDelim('='))
return result;
result.Add(token, state.ReadString());
if (!state.ReadDelim(','))
return result;
token = state.ReadToken();
}
return result;
}
private string ReadToken()
{
var start = _i;
while (_i < _buffer.Length && ValidTokenChar(_buffer[_i]))
_i++;
return _buffer.Substring(start, _i - start);
}
private bool ReadDelim(char ch)
{
while (_i < _buffer.Length && char.IsWhiteSpace(_buffer[_i]))
_i++;
if (_i >= _buffer.Length || _buffer[_i] != ch)
return false;
_i++;
while (_i < _buffer.Length && char.IsWhiteSpace(_buffer[_i]))
_i++;
return true;
}
private string ReadString()
{
if (_i < _buffer.Length && _buffer[_i] == '"')
{
var buffer = new StringBuilder();
_i++;
while (_i < _buffer.Length)
{
if (_buffer[_i] == '\\' && (_i + 1) < _buffer.Length)
{
_i++;
buffer.Append(_buffer[_i]);
_i++;
}
else if (_buffer[_i] == '"')
{
_i++;
return buffer.ToString();
}
else
{
buffer.Append(_buffer[_i]);
_i++;
}
}
return buffer.ToString();
}
else
{
return ReadToken();
}
}
private bool ValidTokenChar(char ch)
{
if (ch < 32)
return false;
if (ch == '(' || ch == ')' || ch == '<' || ch == '>' || ch == '@'
|| ch == ',' || ch == ';' || ch == ':' || ch == '\\' || ch == '"'
|| ch == '/' || ch == '[' || ch == ']' || ch == '?' || ch == '='
|| ch == '{' || ch == '}' || ch == 127 || ch == ' ' || ch == '\t')
return false;
return true;
}
}