Einleitung
Um das CoreOne Suite Application Interface (API) zu benutzen oder auf eine andere über OpenID angebundene Applikation mittels API Benutzer zuzugreifen, muss ein Access-Token gelöst werden. Dieser Artikel beschreibt wie ein solcher Access-Token gelöst werden kann.
Vorbedingungen
Folgende Vorbedingungen müssen erfüllt sein um einen Access Token lösen zu können.
1 | Applikation registrieren | Die Applikation von welcher sie auf das Application Interface zugreifen möchten muss in der CoreOne Suite erfasst sein und mit einem client_secret belegt sein. |
2 | API Benutzer | Sie müssen einen Benutzer eingerichtet haben, der über die Berechtigungen verfügt um die gewünschte API Funktion aufzurufen. |
3 | Token Endpoint | Sie benötigen die URL auf welchem der Token Endpoint konfiguriert ist. Diese sieht in etwa wie folgt aus: |
Access-Token lösen (3rd party lib IdentityModel)
Am einfachsten kann ein gültiger AccessToken mithilfe des nuget-packages IdentityModel gelöst werden.
Eine Beispiel-Konsolenapplikation kann hier heruntergeladen werden
var disco = await DiscoveryClient.GetAsync(discoUri); var tokenClient = new TokenClient(disco.TokenEndpoint, "client-name", "client-secret"); var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("username", "password", "scopes"); if (tokenResponse.IsError) { throw new Exception(tokenResponse.Error); } return tokenResponse.AccessToken
Access-Token lösen (Manuell)
Sind alle Vorbedingungen erfüllt, kann ein Access-Token über folgende Schritte gelöst werden.
1 | Ermitteln des Token Endopoints | Rufen sie den Discovery Endpoint auf. private static async Task<string> GetTokenEndpointUri(string discoUri) { using (var httpClient = new HttpClient()) { //Create a simple GET-Request to the Discovery-Uri var discoDoc = await httpClient.GetStringAsync(discoUri); //return the property token_endpoint from GET-Response var discoElement = (dynamic)JsonConvert.DeserializeObject(discoDoc); return (string)discoElement.token_endpoint; } } |
2 | Zusammenstellen der Parameter | Folgende Parameter müssen im Token Request enthalten sein:
|
3 | Abfragen des Access-Token | Durch ein einfaches HTTP Post auf den zuvor ermittelten Token Endpoint kann der Access-Token gelöst werden. using (var httpClient = new HttpClient()) { //Use Client-Identifier / Client-Secret for Basic-Authentication httpClient.DefaultRequestHeaders.Authorization = new BasicAuthenticationHeaderValue(tokenRequest.ClientIdentifier, tokenRequest.ClientSecret); //Create a POST request to the token-endpoint with data in FormUrlEncoded format var tokenResponse = await httpClient.PostAsync(tokenRequest.TokenEndppointUri, new FormUrlEncodedContent(new Dictionary<string, string> { {"grant_type" , "password"}, {"username", "someUserName" }, {"password", "somePassword" }, {"scope", "openid c1s_api roles" })} })); //return the property access_token from POST-Response var tokenResponseDoc = await tokenResponse.Content.ReadAsStringAsync(); var tokenElement = (dynamic)JsonConvert.DeserializeObject(tokenResponseDoc); var result = (string)tokenElement.access_token; } |
Vollständiges Beispiel (Manuell)
Das oben vereinfachte Beispiel ist hier in kompletter Form zu finden.
using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; namespace ConsoleResourceOwnerFlowRefreshToken { public class Program { public static void Main(string[] args) => MainAsync().GetAwaiter().GetResult(); private static async Task MainAsync() { string tokenEndpoint = null; while (tokenEndpoint == null) { Console.Clear(); Console.WriteLine("Get TokenEndpoint"); try { tokenEndpoint = await GetTokenEndpointUri("https://localhost:5000/.well-known/openid-configuration"); } catch (Exception e) { Console.WriteLine(); Console.WriteLine($"Error: {e}"); Console.WriteLine(); Console.WriteLine("Press q to quit or any other key to retry"); if (char.ToLower(Console.ReadKey().KeyChar) == 'q') return; tokenEndpoint = null; } } var tokenRequest = new TokenRequest { TokenEndppointUri = tokenEndpoint, Scopes = new[] { "openid", "c1s_api", "roles" }, ClientIdentifier = "anyClient", ClientSecret = "anySecret", Username = "someUserName", Password = "someUserPassword" }; do { Console.Clear(); try { Console.WriteLine($"Token-Endpoint: {tokenEndpoint}"); Console.WriteLine(); var token = await GetToken(tokenRequest); Console.WriteLine(token ?? "null"); } catch (Exception e) { Console.WriteLine($"Error: {e}"); } Console.WriteLine(); Console.WriteLine("Press q to quit or any other key to renew token"); } while (char.ToLower(Console.ReadKey().KeyChar) != 'q'); } private static async Task<string> GetToken(TokenRequest tokenRequest) { using (var httpClient = new HttpClient()) { //Use Client-Identifier / Client-Secret for Basic-Authentication httpClient.DefaultRequestHeaders.Authorization = new BasicAuthenticationHeaderValue(tokenRequest.ClientIdentifier, tokenRequest.ClientSecret); //Create a POST request to the token-endpoint with data in FormUrlEncoded format var tokenResponse = await httpClient.PostAsync(tokenRequest.TokenEndppointUri, new FormUrlEncodedContent(new Dictionary<string, string> { {"grant_type" , "password"}, {"username", tokenRequest.Username }, {"password", tokenRequest.Password }, {"scope", string.Join(" ", tokenRequest.Scopes)} })); //return the property access_token from POST-Response var tokenResponseDoc = await tokenResponse.Content.ReadAsStringAsync(); var tokenElement = (dynamic)JsonConvert.DeserializeObject(tokenResponseDoc); return (string)tokenElement.access_token; } } private static async Task<string> GetTokenEndpointUri(string discoUri) { using (var httpClient = new HttpClient()) { //Create a simple GET-Request to the Discovery-Uri var discoDoc = await httpClient.GetStringAsync(discoUri); //return the property token_endpoint from GET-Response var discoElement = (dynamic)JsonConvert.DeserializeObject(discoDoc); return (string)discoElement.token_endpoint; } } } public class TokenRequest { public string TokenEndppointUri { get; set; } public string ClientIdentifier { get; set; } public string ClientSecret { get; set; } public string Username { get; set; } public string Password { get; set; } public string[] Scopes { get; set; } } }
Postman
In Postman kann auch direkt ein Token gelöst werden. Dafür muss unter Authorization der Typ OAuth 2.0 ausgewählt werden.