mirror of
https://github.com/Sarsoo/Spotify.NET.git
synced 2024-12-23 14:46:26 +00:00
Added first OAuth request: client credentials
This commit is contained in:
parent
fee995f984
commit
9b8a4cd2c9
8
.vscode/csharp.code-snippets
vendored
8
.vscode/csharp.code-snippets
vendored
@ -1,7 +1,7 @@
|
||||
{
|
||||
"model-class": {
|
||||
"class-model": {
|
||||
"scope": "csharp",
|
||||
"prefix": "model-class",
|
||||
"prefix": "class-model",
|
||||
"body": [
|
||||
"namespace SpotifyAPI.Web",
|
||||
"{",
|
||||
@ -15,9 +15,9 @@
|
||||
],
|
||||
"description": "Creates a new model"
|
||||
},
|
||||
"request-class": {
|
||||
"class-request": {
|
||||
"scope": "csharp",
|
||||
"prefix": "request-class",
|
||||
"prefix": "class-request",
|
||||
"body": [
|
||||
"namespace SpotifyAPI.Web",
|
||||
"{",
|
||||
|
@ -37,9 +37,9 @@ namespace SpotifyAPI.Web
|
||||
Assert.AreEqual(null, defaultConfig.HTTPLogger);
|
||||
Assert.AreEqual(null, defaultConfig.RetryHandler);
|
||||
|
||||
Assert.IsInstanceOf(typeof(TokenHeaderAuthenticator), defaultConfig.Authenticator);
|
||||
Assert.IsInstanceOf(typeof(TokenAuthenticator), defaultConfig.Authenticator);
|
||||
|
||||
var tokenHeaderAuth = defaultConfig.Authenticator as TokenHeaderAuthenticator;
|
||||
var tokenHeaderAuth = defaultConfig.Authenticator as TokenAuthenticator;
|
||||
Assert.AreEqual(token, tokenHeaderAuth.Token);
|
||||
Assert.AreEqual(tokenType, tokenHeaderAuth.TokenType);
|
||||
}
|
||||
@ -51,7 +51,7 @@ namespace SpotifyAPI.Web
|
||||
var defaultConfig = SpotifyClientConfig.CreateDefault();
|
||||
var tokenConfig = defaultConfig.WithToken(token);
|
||||
|
||||
Assert.AreEqual(token, (tokenConfig.Authenticator as TokenHeaderAuthenticator).Token);
|
||||
Assert.AreEqual(token, (tokenConfig.Authenticator as TokenAuthenticator).Token);
|
||||
Assert.AreNotEqual(defaultConfig, tokenConfig);
|
||||
Assert.AreEqual(null, defaultConfig.Authenticator);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ namespace SpotifyAPI.Web.Tests
|
||||
);
|
||||
await apiConnector.SendAPIRequest<string>(new Uri("/me", UriKind.Relative), HttpMethod.Get).ConfigureAwait(false);
|
||||
|
||||
authenticator.Verify(a => a.Apply(It.IsAny<IRequest>()), Times.Once);
|
||||
authenticator.Verify(a => a.Apply(It.IsAny<IRequest>(), It.IsAny<IAPIConnector>()), Times.Once);
|
||||
httpClient.Verify(h => h.DoRequest(It.IsAny<IRequest>()), Times.Once);
|
||||
serializer.Verify(s => s.DeserializeResponse<string>(response.Object), Times.Once);
|
||||
}
|
||||
@ -89,7 +89,7 @@ namespace SpotifyAPI.Web.Tests
|
||||
await apiConnector.SendAPIRequest<string>(new Uri("/me", UriKind.Relative), HttpMethod.Get).ConfigureAwait(false);
|
||||
|
||||
serializer.Verify(s => s.SerializeRequest(It.IsAny<IRequest>()), Times.Once);
|
||||
authenticator.Verify(a => a.Apply(It.IsAny<IRequest>()), Times.Exactly(2));
|
||||
authenticator.Verify(a => a.Apply(It.IsAny<IRequest>(), It.IsAny<IAPIConnector>()), Times.Exactly(2));
|
||||
httpClient.Verify(h => h.DoRequest(It.IsAny<IRequest>()), Times.Exactly(2));
|
||||
serializer.Verify(s => s.DeserializeResponse<string>(response.Object), Times.Once);
|
||||
}
|
||||
|
@ -6,16 +6,18 @@ using SpotifyAPI.Web.Http;
|
||||
namespace SpotifyAPI.Web.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TokenHeaderAuthenticatorTest
|
||||
public class TokenAuthenticatorTest
|
||||
{
|
||||
[Test]
|
||||
public void Apply_AddsCorrectHeader()
|
||||
{
|
||||
var authenticator = new TokenHeaderAuthenticator("MyToken", "Bearer");
|
||||
var authenticator = new TokenAuthenticator("MyToken", "Bearer");
|
||||
var request = new Mock<IRequest>();
|
||||
var apiConnector = new Mock<IAPIConnector>();
|
||||
|
||||
request.SetupGet(r => r.Headers).Returns(new Dictionary<string, string>());
|
||||
|
||||
authenticator.Apply(request.Object);
|
||||
authenticator.Apply(request.Object, apiConnector.Object);
|
||||
Assert.AreEqual(request.Object.Headers["Authorization"], "Bearer MyToken");
|
||||
}
|
||||
}
|
@ -11,6 +11,6 @@ namespace SpotifyAPI.Web
|
||||
API = apiConnector;
|
||||
}
|
||||
|
||||
public IAPIConnector API { get; set; }
|
||||
protected IAPIConnector API { get; set; }
|
||||
}
|
||||
}
|
||||
|
9
SpotifyAPI.Web/Clients/Interfaces/IOAuthClient.cs
Normal file
9
SpotifyAPI.Web/Clients/Interfaces/IOAuthClient.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SpotifyAPI.Web
|
||||
{
|
||||
public interface IOAuthClient
|
||||
{
|
||||
Task<TokenResponse> RequestToken(ClientCredentialsRequest request);
|
||||
}
|
||||
}
|
49
SpotifyAPI.Web/Clients/OAuthClient.cs
Normal file
49
SpotifyAPI.Web/Clients/OAuthClient.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using SpotifyAPI.Web.Http;
|
||||
|
||||
namespace SpotifyAPI.Web
|
||||
{
|
||||
public class OAuthClient : APIClient, IOAuthClient
|
||||
{
|
||||
public OAuthClient(IAPIConnector apiConnector) : base(apiConnector) { }
|
||||
public OAuthClient() : this(SpotifyClientConfig.CreateDefault()) { }
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062")]
|
||||
public OAuthClient(SpotifyClientConfig config) : base(ValidateConfig(config)) { }
|
||||
|
||||
public Task<TokenResponse> RequestToken(ClientCredentialsRequest request)
|
||||
{
|
||||
Ensure.ArgumentNotNull(request, nameof(request));
|
||||
|
||||
var form = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("grant_type", "client_credentials")
|
||||
};
|
||||
|
||||
var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{request.ClientId}:{request.ClientSecret}"));
|
||||
var headers = new Dictionary<string, string>
|
||||
{
|
||||
{ "Authorization", $"Basic {base64}"}
|
||||
};
|
||||
|
||||
return API.Post<TokenResponse>(SpotifyUrls.OAuthToken, null, new FormUrlEncodedContent(form), headers);
|
||||
}
|
||||
|
||||
private static APIConnector ValidateConfig(SpotifyClientConfig config)
|
||||
{
|
||||
Ensure.ArgumentNotNull(config, nameof(config));
|
||||
return new APIConnector(
|
||||
config.BaseAddress,
|
||||
config.Authenticator,
|
||||
config.JSONSerializer,
|
||||
config.HTTPClient,
|
||||
config.RetryHandler,
|
||||
config.HTTPLogger
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -49,7 +49,7 @@ namespace SpotifyAPI.Web
|
||||
|
||||
return new SpotifyClientConfig(
|
||||
BaseAddress,
|
||||
new TokenHeaderAuthenticator(token, tokenType),
|
||||
new TokenAuthenticator(token, tokenType),
|
||||
JSONSerializer,
|
||||
HTTPClient,
|
||||
RetryHandler,
|
||||
@ -147,7 +147,7 @@ namespace SpotifyAPI.Web
|
||||
|
||||
public static SpotifyClientConfig CreateDefault(string token, string tokenType = "Bearer")
|
||||
{
|
||||
return CreateDefault().WithAuthenticator(new TokenHeaderAuthenticator(token, tokenType));
|
||||
return CreateDefault().WithAuthenticator(new TokenAuthenticator(token, tokenType));
|
||||
}
|
||||
|
||||
public static SpotifyClientConfig CreateDefault()
|
||||
|
@ -106,6 +106,13 @@ namespace SpotifyAPI.Web.Http
|
||||
return SendAPIRequest<T>(uri, HttpMethod.Post, parameters, body);
|
||||
}
|
||||
|
||||
public Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters, object body, Dictionary<string, string> headers)
|
||||
{
|
||||
Ensure.ArgumentNotNull(uri, nameof(uri));
|
||||
|
||||
return SendAPIRequest<T>(uri, HttpMethod.Post, parameters, body, headers);
|
||||
}
|
||||
|
||||
public async Task<HttpStatusCode> Post(Uri uri, IDictionary<string, string> parameters, object body)
|
||||
{
|
||||
Ensure.ArgumentNotNull(uri, nameof(uri));
|
||||
@ -160,13 +167,14 @@ namespace SpotifyAPI.Web.Http
|
||||
Uri uri,
|
||||
HttpMethod method,
|
||||
IDictionary<string, string> parameters,
|
||||
object body
|
||||
object body,
|
||||
IDictionary<string, string> headers
|
||||
)
|
||||
{
|
||||
Ensure.ArgumentNotNull(uri, nameof(uri));
|
||||
Ensure.ArgumentNotNull(method, nameof(method));
|
||||
|
||||
return new Request(new Dictionary<string, string>(), parameters)
|
||||
return new Request(headers ?? new Dictionary<string, string>(), parameters ?? new Dictionary<string, string>())
|
||||
{
|
||||
BaseAddress = _baseAddress,
|
||||
Endpoint = uri,
|
||||
@ -184,7 +192,10 @@ namespace SpotifyAPI.Web.Http
|
||||
|
||||
private async Task<IResponse> DoRequest(IRequest request)
|
||||
{
|
||||
await _authenticator.Apply(request).ConfigureAwait(false);
|
||||
if (_authenticator != null)
|
||||
{
|
||||
await _authenticator.Apply(request, this).ConfigureAwait(false);
|
||||
}
|
||||
_httpLogger?.OnRequest(request);
|
||||
IResponse response = await _httpClient.DoRequest(request).ConfigureAwait(false);
|
||||
_httpLogger?.OnResponse(response);
|
||||
@ -192,7 +203,10 @@ namespace SpotifyAPI.Web.Http
|
||||
{
|
||||
response = await _retryHandler.HandleRetry(request, response, async (newRequest) =>
|
||||
{
|
||||
await _authenticator.Apply(newRequest).ConfigureAwait(false);
|
||||
if (_authenticator != null)
|
||||
{
|
||||
await _authenticator.Apply(request, this).ConfigureAwait(false);
|
||||
}
|
||||
var newResponse = await _httpClient.DoRequest(request).ConfigureAwait(false);
|
||||
_httpLogger?.OnResponse(newResponse);
|
||||
return newResponse;
|
||||
@ -206,10 +220,11 @@ namespace SpotifyAPI.Web.Http
|
||||
Uri uri,
|
||||
HttpMethod method,
|
||||
IDictionary<string, string> parameters = null,
|
||||
object body = null
|
||||
object body = null,
|
||||
IDictionary<string, string> headers = null
|
||||
)
|
||||
{
|
||||
var request = CreateRequest(uri, method, parameters, body);
|
||||
var request = CreateRequest(uri, method, parameters, body, headers);
|
||||
return DoRequest(request);
|
||||
}
|
||||
|
||||
@ -217,10 +232,11 @@ namespace SpotifyAPI.Web.Http
|
||||
Uri uri,
|
||||
HttpMethod method,
|
||||
IDictionary<string, string> parameters = null,
|
||||
object body = null
|
||||
object body = null,
|
||||
IDictionary<string, string> headers = null
|
||||
)
|
||||
{
|
||||
var request = CreateRequest(uri, method, parameters, body);
|
||||
var request = CreateRequest(uri, method, parameters, body, headers);
|
||||
IAPIResponse<T> apiResponse = await DoSerializedRequest<T>(request).ConfigureAwait(false);
|
||||
return apiResponse.Body;
|
||||
}
|
||||
@ -229,10 +245,11 @@ namespace SpotifyAPI.Web.Http
|
||||
Uri uri,
|
||||
HttpMethod method,
|
||||
IDictionary<string, string> parameters = null,
|
||||
object body = null
|
||||
object body = null,
|
||||
IDictionary<string, string> headers = null
|
||||
)
|
||||
{
|
||||
var request = CreateRequest(uri, method, parameters, body);
|
||||
var request = CreateRequest(uri, method, parameters, body, headers);
|
||||
var response = await DoSerializedRequest<object>(request).ConfigureAwait(false);
|
||||
return response.Response;
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace SpotifyAPI.Web.Http
|
||||
{
|
||||
public class TokenHeaderAuthenticator : IAuthenticator
|
||||
public class TokenAuthenticator : IAuthenticator
|
||||
{
|
||||
public TokenHeaderAuthenticator(string token, string tokenType)
|
||||
public TokenAuthenticator(string token, string tokenType)
|
||||
{
|
||||
Token = token;
|
||||
TokenType = tokenType;
|
||||
@ -14,7 +14,7 @@ namespace SpotifyAPI.Web.Http
|
||||
|
||||
public string TokenType { get; set; }
|
||||
|
||||
public Task Apply(IRequest request)
|
||||
public Task Apply(IRequest request, IAPIConnector apiConnector)
|
||||
{
|
||||
Ensure.ArgumentNotNull(request, nameof(request));
|
||||
|
@ -24,6 +24,7 @@ namespace SpotifyAPI.Web.Http
|
||||
Task<T> Post<T>(Uri uri);
|
||||
Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters);
|
||||
Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters, object body);
|
||||
Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters, object body, Dictionary<string, string> headers);
|
||||
Task<HttpStatusCode> Post(Uri uri, IDictionary<string, string> parameters, object body);
|
||||
|
||||
Task<T> Put<T>(Uri uri);
|
||||
@ -37,7 +38,11 @@ namespace SpotifyAPI.Web.Http
|
||||
Task<T> Delete<T>(Uri uri, IDictionary<string, string> parameters, object body);
|
||||
Task<HttpStatusCode> Delete(Uri uri, IDictionary<string, string> parameters, object body);
|
||||
|
||||
Task<T> SendAPIRequest<T>(Uri uri, HttpMethod method, IDictionary<string, string> parameters = null, object body = null);
|
||||
Task<T> SendAPIRequest<T>(
|
||||
Uri uri, HttpMethod method,
|
||||
IDictionary<string, string> parameters = null,
|
||||
object body = null,
|
||||
IDictionary<string, string> headers = null);
|
||||
|
||||
void SetRequestTimeout(TimeSpan timeout);
|
||||
}
|
||||
|
@ -4,6 +4,6 @@ namespace SpotifyAPI.Web.Http
|
||||
{
|
||||
public interface IAuthenticator
|
||||
{
|
||||
Task Apply(IRequest request);
|
||||
Task Apply(IRequest request, IAPIConnector apiConnector);
|
||||
}
|
||||
}
|
||||
|
16
SpotifyAPI.Web/Models/Request/CredentialsRequest.cs
Normal file
16
SpotifyAPI.Web/Models/Request/CredentialsRequest.cs
Normal file
@ -0,0 +1,16 @@
|
||||
namespace SpotifyAPI.Web
|
||||
{
|
||||
public class ClientCredentialsRequest
|
||||
{
|
||||
public ClientCredentialsRequest(string clientId, string clientSecret)
|
||||
{
|
||||
Ensure.ArgumentNotNullOrEmptyString(clientId, nameof(clientId));
|
||||
Ensure.ArgumentNotNullOrEmptyString(clientSecret, nameof(clientSecret));
|
||||
|
||||
ClientId = clientId;
|
||||
ClientSecret = clientSecret;
|
||||
}
|
||||
public string ClientId { get; }
|
||||
public string ClientSecret { get; }
|
||||
}
|
||||
}
|
9
SpotifyAPI.Web/Models/Response/Token.cs
Normal file
9
SpotifyAPI.Web/Models/Response/Token.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace SpotifyAPI.Web
|
||||
{
|
||||
public class TokenResponse
|
||||
{
|
||||
public string AccessToken { get; set; }
|
||||
public string TokenType { get; set; }
|
||||
public int ExpiresIn { get; set; }
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.1</TargetFrameworks>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<!-- <GenerateDocumentationFile>true</GenerateDocumentationFile> -->
|
||||
<PackageId>SpotifyAPI.Web</PackageId>
|
||||
<Title>SpotifyAPI.Web</Title>
|
||||
<Authors>Jonas Dellinger</Authors>
|
||||
|
@ -7,6 +7,8 @@ namespace SpotifyAPI.Web
|
||||
|
||||
public static readonly Uri APIV1 = new Uri("https://api.spotify.com/v1/");
|
||||
|
||||
public static readonly Uri OAuthToken = new Uri("https://accounts.spotify.com/api/token");
|
||||
|
||||
public static Uri Me() => EUri($"me");
|
||||
|
||||
public static Uri User(string userId) => EUri($"users/{userId}");
|
||||
|
Loading…
Reference in New Issue
Block a user