Как получить токен аутентификации OAuth 2.0 в С#
У меня есть эти настройки:
Затем мне нужно позвонить с использованием токена на предъявителя в заголовке.
Я могу заставить это работать в Почтальоне, но наткнулся на стену, пытаясь решить, как реализовать это в С#. Я использую RestSharp (но открыт для других). Все это кажется настолько непрозрачным, когда я думал, что это будет довольно просто: это консольное приложение, поэтому мне не нужны навороты.
В конечном итоге я хочу, чтобы мое приложение (программно) получило токен, а затем использовало его для моих последующих вызовов. Я был бы признателен всем, кто указал мне на документацию или примеры, которые ясно объясняют, что я ищу. Все, с чем я сталкивался, частично или для служб, работающих в другом потоке.
Благодарю.
Ответы
Ответ 1
В "Почтальоне" нажмите "Создать код", а затем в диалоговом окне "Создать фрагменты кода" вы можете выбрать другой язык кодирования, включая С# (RestSharp).
Кроме того, вам нужен только URL токена доступа. Параметры формы тогда:
grant_type=client_credentials
client_id=abc
client_secret=123
Фрагмент кода:
/* using RestSharp; // https://www.nuget.org/packages/RestSharp/ */
var client = new RestClient("https://service.endpoint.com/api/oauth2/token");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=client_credentials&client_id=abc&client_secret=123", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Из тела ответа вы можете получить свой токен доступа. Например, для типа токена Bearer вы можете добавить следующий заголовок к последующим аутентифицированным запросам:
request.AddHeader("authorization", "Bearer <access_token>");
Ответ 2
Ответ Rest Client идеален! (Я проголосовал за это)
Но, на всякий случай, если вы хотите пойти "сырой"
..........
Я получил это для работы с HttpClient.
/*
.nuget\packages\newtonsoft.json\12.0.1
.nuget\packages\system.net.http\4.3.4
*/
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web;
private static async Task<Token> GetElibilityToken(HttpClient client)
{
string baseAddress = @"https://blah.blah.blah.com/token";
string grant_type = "client_credentials";
string client_id = "myId";
string client_secret = "shhhhhhhhhhhhhhItsSecret";
var form = new Dictionary<string, string>
{
{"grant_type", grant_type},
{"client_id", client_id},
{"client_secret", client_secret},
};
HttpResponseMessage tokenResponse = await client.PostAsync(baseAddress, new FormUrlEncodedContent(form));
var jsonContent = await tokenResponse.Content.ReadAsStringAsync();
Token tok = JsonConvert.DeserializeObject<Token>(jsonContent);
return tok;
}
internal class Token
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty("refresh_token")]
public string RefreshToken { get; set; }
}
Вот еще один рабочий пример (основанный на ответе выше)...... с еще несколькими изменениями. Иногда сервис токенов является привередливым:
private static async Task<Token> GetATokenToTestMyRestApiUsingHttpClient(HttpClient client)
{
/* this code has lots of commented out stuff with different permutations of tweaking the request */
/* this is a version of asking for token using HttpClient. aka, an alternate to using default libraries instead of RestClient */
OAuthValues oav = GetOAuthValues(); /* object has has simple string properties for TokenUrl, GrantType, ClientId and ClientSecret */
var form = new Dictionary<string, string>
{
{ "grant_type", oav.GrantType },
{ "client_id", oav.ClientId },
{ "client_secret", oav.ClientSecret }
};
/* now tweak the http client */
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("cache-control", "no-cache");
/* try 1 */
////client.DefaultRequestHeaders.Add("content-type", "application/x-www-form-urlencoded");
/* try 2 */
////client.DefaultRequestHeaders .Accept .Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));//ACCEPT header
/* try 3 */
////does not compile */client.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
////application/x-www-form-urlencoded
HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, oav.TokenUrl);
/////req.RequestUri = new Uri(baseAddress);
req.Content = new FormUrlEncodedContent(form);
////string jsonPayload = "{\"grant_type\":\"" + oav.GrantType + "\",\"client_id\":\"" + oav.ClientId + "\",\"client_secret\":\"" + oav.ClientSecret + "\"}";
////req.Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");//CONTENT-TYPE header
req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
/* now make the request */
////HttpResponseMessage tokenResponse = await client.PostAsync(baseAddress, new FormUrlEncodedContent(form));
HttpResponseMessage tokenResponse = await client.SendAsync(req);
Console.WriteLine(string.Format("HttpResponseMessage.ReasonPhrase='{0}'", tokenResponse.ReasonPhrase));
if (!tokenResponse.IsSuccessStatusCode)
{
throw new HttpRequestException("Call to get Token with HttpClient failed.");
}
var jsonContent = await tokenResponse.Content.ReadAsStringAsync();
Token tok = JsonConvert.DeserializeObject<Token>(jsonContent);
return tok;
}
Ответ 3
В этом примере показано, как получить токен HttpWebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(pathapi);
request.Method = "POST";
string postData = "grant_type=password";
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] byte1 = encoding.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byte1.Length;
Stream newStream = request.GetRequestStream();
newStream.Write(byte1, 0, byte1.Length);
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
using (Stream responseStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
getreaderjson = reader.ReadToEnd();
}
Ответ 4
Очевидно:
Пример создания токена на стороне сервера
private string GenerateToken(string userName)
{
var someClaims = new Claim[]{
new Claim(JwtRegisteredClaimNames.UniqueName, userName),
new Claim(JwtRegisteredClaimNames.Email, GetEmail(userName)),
new Claim(JwtRegisteredClaimNames.NameId,Guid.NewGuid().ToString())
};
SecurityKey securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_settings.Tokenizer.Key));
var token = new JwtSecurityToken(
issuer: _settings.Tokenizer.Issuer,
audience: _settings.Tokenizer.Audience,
claims: someClaims,
expires: DateTime.Now.AddHours(_settings.Tokenizer.ExpiryHours),
signingCredentials: new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256)
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
(примечание: Tokenizer - это мой вспомогательный класс, содержащий аудиторию эмитента и т.д.)
Определенно:
Клиентская сторона получает токен для аутентификации
public async Task<string> GetToken()
{
string token = "";
var siteSettings = DependencyResolver.Current.GetService<SiteSettings>();
var client = new HttpClient();
client.BaseAddress = new Uri(siteSettings.PopularSearchRequest.StaticApiUrl);
client.DefaultRequestHeaders.Accept.Clear();
//client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
StatisticUserModel user = new StatisticUserModel()
{
Password = siteSettings.PopularSearchRequest.Password,
Username = siteSettings.PopularSearchRequest.Username
};
string jsonUser = JsonConvert.SerializeObject(user, Formatting.Indented);
var stringContent = new StringContent(jsonUser, Encoding.UTF8, "application/json");
var response = await client.PostAsync(siteSettings.PopularSearchRequest.StaticApiUrl + "/api/token/new", stringContent);
token = await response.Content.ReadAsStringAsync();
return token;
}
Вы можете использовать этот токен для авторизации (то есть в последующих запросах)
Ответ 5
Вот полный пример. Щелкните правой кнопкой мыши по решению, чтобы управлять пакетами nuget и получить Newtonsoft и RestSharp:
using Newtonsoft.Json.Linq;
using RestSharp;
using System;
namespace TestAPI
{
class Program
{
static void Main(string[] args)
{
String id = "xxx";
String secret = "xxx";
var client = new RestClient("https://xxx.xxx.com/services/api/oauth2/token");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=client_credentials&scope=all&client_id=" + id + "&client_secret=" + secret, ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
dynamic resp = JObject.Parse(response.Content);
String token = resp.access_token;
client = new RestClient("https://xxx.xxx.com/services/api/x/users/v1/employees");
request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Bearer " + token);
request.AddHeader("cache-control", "no-cache");
response = client.Execute(request);
}
}
}
Ответ 6
Я использовал ADAL.NET/Microsoft Identity Platform для достижения этой цели. Преимущество его использования состояло в том, что мы получаем красивую оболочку вокруг кода для приобретения AccessToken
и получаем дополнительные функции, такие как Token Cache
, из коробки. Из документации:
Why use ADAL.NET?
ADAL.NET V3 (библиотека аутентификации Active Directory для .NET) позволяет разработчикам приложений .NET приобретать токены для вызова защищенных веб-API. Этими веб-API могут быть Microsoft Graph или сторонние веб-API.
Вот фрагмент кода:
// Import Nuget package: Microsoft.Identity.Client
public class AuthenticationService
{
private readonly List<string> _scopes;
private readonly IConfidentialClientApplication _app;
public AuthenticationService(AuthenticationConfiguration authentication)
{
_app = ConfidentialClientApplicationBuilder
.Create(authentication.ClientId)
.WithClientSecret(authentication.ClientSecret)
.WithAuthority(authentication.Authority)
.Build();
_scopes = new List<string> {$"{authentication.Audience}/.default"};
}
public async Task<string> GetAccessToken()
{
var authenticationResult = await _app.AcquireTokenForClient(_scopes)
.ExecuteAsync();
return authenticationResult.AccessToken;
}
}