Просмотр исходного кода

fixed authorization with spotify

tags/v1.1.0^2
anastasijasavov 3 лет назад
Родитель
Сommit
d9a8bda60d

+ 0
- 16
GrpcShared/DTO/Auth/AuthParams.cs Просмотреть файл

using ProtoBuf;

namespace GrpcShared
{
[ProtoContract]
public class AuthParams
{
[ProtoMember(1)]
public string ClientId { get; set; }
[ProtoMember(2)]
public string RedirectURI { get; set; }
[ProtoMember(3)]
public string Scope { get; set; }
}
}

+ 0
- 26
GrpcShared/DTO/Auth/AuthRequest.cs Просмотреть файл

using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GrpcShared.DTO.Auth
{
[ProtoContract]
public class AuthRequest
{
[ProtoMember(1)]
public string ClientId { get; set; }
[ProtoMember(2)]
public string ClientSecret { get; set; }
[ProtoMember(3)]
public string RedirectURI { get; set; }
[ProtoMember(4)]
public string ResponseType { get; set; } = "track";
[ProtoMember(5)]
public string Scope { get; set; }
[ProtoMember(6)]
public string ShowDialog{ get; set; }
}
}

+ 28
- 0
GrpcShared/DTO/Auth/CodeRequest.cs Просмотреть файл

using ProtoBuf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GrpcShared.DTO.Auth
{
[ProtoContract]
public class CodeRequest
{
[ProtoMember(1)]
public string? ClientId { get; set; }
[ProtoMember(2)]
public string? ClientSecret { get; set; }
[ProtoMember(3)]
public string? RedirectURI { get; set; }
[ProtoMember(4)]
public string ResponseType { get; set; } = "code";
[ProtoMember(5)]
public string? Scope { get; set; }
[ProtoMember(6)]
[DefaultValue(true)]
public bool ShowDialog { get; set; } = true;
}
}

+ 0
- 16
GrpcShared/DTO/Auth/CodeResponse.cs Просмотреть файл

using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GrpcShared.DTO.Auth
{
[ProtoContract]
public class CodeResponse
{
[ProtoMember(1)]
public string Code { get; set; }
}
}

+ 22
- 0
GrpcShared/DTO/Auth/TokenRequest.cs Просмотреть файл

using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GrpcShared.DTO.Auth
{
[ProtoContract]
public class TokenRequest
{
[ProtoMember(1)]
public string grant_type { get; set; } = "authorization_code";
[ProtoMember(2)]
public string? code { get; set; }
[ProtoMember(3)]
public string? redirect_uri { get; set; }

}
}

GrpcShared/DTO/Auth/AuthResponse.cs → GrpcShared/DTO/Auth/TokenResponse.cs Просмотреть файл

namespace GrpcShared.DTO.Auth namespace GrpcShared.DTO.Auth
{ {
[ProtoContract] [ProtoContract]
public class AuthResponse
public class TokenResponse
{ {
[ProtoMember(1)] [ProtoMember(1)]
public string AccessToken { get; set; }
public string? AccessToken { get; set; }
[ProtoMember(2)] [ProtoMember(2)]
public string RefreshToken{ get; set; }
public string? RefreshToken{ get; set; }
[ProtoMember(3)]
public int? ExpiresIn { get; set; }
} }
} }

+ 3
- 3
GrpcShared/Interfaces/IAuthService.cs Просмотреть файл

[Service] [Service]
public interface IAuthService public interface IAuthService
{ {
Task<CodeResponse> GetCode(AuthRequest request);
Task<AuthResponse> GetAccessToken(CodeResponse code);
Task<AuthParams> GetAuthParams();
Task<TokenResponse> GetAccessToken(TokenRequest code);
Task<CodeRequest> GetAuthParams();
//Task<ClientSecrets> GetClientSecrets();
} }
} }

+ 1
- 0
IdentityProvider/IdentityProvider.csproj Просмотреть файл

<PackageReference Include="Grpc.AspNetCore" Version="2.40.0" /> <PackageReference Include="Grpc.AspNetCore" Version="2.40.0" />
<PackageReference Include="Grpc.AspNetCore.Web" Version="2.47.0" /> <PackageReference Include="Grpc.AspNetCore.Web" Version="2.47.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="6.0.8" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="6.0.8" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="protobuf-net.Grpc" Version="1.0.171" /> <PackageReference Include="protobuf-net.Grpc" Version="1.0.171" />
<PackageReference Include="protobuf-net.Grpc.AspNetCore" Version="1.0.152" /> <PackageReference Include="protobuf-net.Grpc.AspNetCore" Version="1.0.152" />
<PackageReference Include="protobuf-net.Grpc.AspNetCore.Reflection" Version="1.0.152" /> <PackageReference Include="protobuf-net.Grpc.AspNetCore.Reflection" Version="1.0.152" />

+ 6
- 1
IdentityProvider/Program.cs Просмотреть файл

using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using ProtoBuf.Grpc.Server; using ProtoBuf.Grpc.Server;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using GrpcShared.DTO.Auth;


var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
#if DEBUG #if DEBUG
builder.Services.AddOptions(); builder.Services.AddOptions();
// Additional configuration is required to successfully run gRPC on macOS. // Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
builder.Services.Configure<AuthParams>(builder.Configuration.GetSection("AuthParams"));
builder.Services.Configure<CodeRequest>(builder.Configuration.GetSection("AuthParams"));
builder.Services.AddControllersWithViews(); builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages(); builder.Services.AddRazorPages();


builder.Services.AddGrpc(); builder.Services.AddGrpc();
builder.Services.AddCodeFirstGrpc(); builder.Services.AddCodeFirstGrpc();
builder.Services.AddCodeFirstGrpcReflection(); builder.Services.AddCodeFirstGrpcReflection();
//call spotify api
builder.Services.AddHttpClient();


var app = builder.Build(); var app = builder.Build();




app.UseHttpsRedirection(); app.UseHttpsRedirection();


//run blazor project by running grpc server
app.UseBlazorFrameworkFiles(); app.UseBlazorFrameworkFiles();
app.UseStaticFiles(); app.UseStaticFiles();


app.UseRouting(); app.UseRouting();


//for http2 -> http conversion
app.UseGrpcWeb(); app.UseGrpcWeb();


app.MapRazorPages(); app.MapRazorPages();

+ 47
- 11
IdentityProvider/Services/AuthService.cs Просмотреть файл

//using IdentityProvider.Protos.AuthService; //using IdentityProvider.Protos.AuthService;
using Grpc.Net.Client;
using GrpcShared; using GrpcShared;
using GrpcShared.DTO.Auth; using GrpcShared.DTO.Auth;
using GrpcShared.Interfaces; using GrpcShared.Interfaces;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;


namespace IdentityProvider.Services namespace IdentityProvider.Services
{ {
public class AuthService : IAuthService public class AuthService : IAuthService
{ {
private readonly ILogger<AuthService> _logger; private readonly ILogger<AuthService> _logger;
private readonly AuthParams _params;
public AuthService(ILogger<AuthService> logger, IOptions<AuthParams> options )
private readonly CodeRequest _params;
private readonly IHttpClientFactory _httpClientFactory;
public AuthService(ILogger<AuthService> logger, IOptions<CodeRequest> options, IHttpClientFactory httpClientFactory)
{ {
_logger = logger; _logger = logger;
_params = options.Value; _params = options.Value;
_httpClientFactory = httpClientFactory;
} }




public Task<AuthResponse> GetAccessToken(CodeResponse code)
public async Task<TokenResponse> GetAccessToken(TokenRequest tokenRequest)
{ {
throw new NotImplementedException();
}
var http = _httpClientFactory.CreateClient();


public Task<CodeResponse> GetCode(AuthRequest request)
{
throw new NotImplementedException();
string url = "https://accounts.spotify.com/api/token";
http.BaseAddress = new Uri(url);
//get client id and secret from appsettings, convert to base64 and set as header
var secrets = await GetAuthParams();
byte[] contentType = Encoding.UTF8.GetBytes($"{secrets.ClientId}:{secrets.ClientSecret}");

http.DefaultRequestHeaders.Add(HeaderNames.Authorization, "Basic " + Convert.ToBase64String(contentType));

//ACCEPT HEADER
http.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));

//BODY
var requestBody = new Dictionary<string, string>();
requestBody["grant_type"] = tokenRequest.grant_type;
requestBody["code"] = tokenRequest.code!;
requestBody["redirect_uri"] = secrets.RedirectURI!;

var response = await http.PostAsync(url, new FormUrlEncodedContent(requestBody));

var contents = JsonConvert.DeserializeObject<TokenResponse>(await response.Content.ReadAsStringAsync());
return await Task.FromResult(new TokenResponse
{
AccessToken = contents!.AccessToken,
RefreshToken = contents!.RefreshToken,
ExpiresIn = contents!.ExpiresIn
});
} }


public async Task<AuthParams> GetAuthParams()
public async Task<CodeRequest> GetAuthParams()
{ {
var authParams = new AuthParams {
var authParams = new CodeRequest
{
ClientId = _params.ClientId, ClientId = _params.ClientId,
RedirectURI = _params.RedirectURI, RedirectURI = _params.RedirectURI,
Scope =_params.Scope };
Scope = _params.Scope,
ClientSecret = _params.ClientSecret
};
return await Task.FromResult(authParams); return await Task.FromResult(authParams);
} }

} }
} }

+ 2
- 1
IdentityProvider/appsettings.json Просмотреть файл

"AuthParams": { "AuthParams": {
"ClientId": "83e1d09876b049c4bb1953185a4b3bfb", "ClientId": "83e1d09876b049c4bb1953185a4b3bfb",
"RedirectURI": "https://localhost:44342/callback", "RedirectURI": "https://localhost:44342/callback",
"Scope": "user-read-currently-playing user-read-email user-library-modify user-top-read"
"Scope": "user-read-currently-playing user-read-email user-library-modify user-top-read",
"ClientSecret": "ea752433d0774fad87fab5c1ee788c8d"
} }
} }

+ 33
- 0
NemAnCore/Pages/Callback.razor Просмотреть файл

@page "/callback"
@using NemAnBlazor.Services.Interfaces
@inject NavigationManager NavigationMgr
@inject IAuthClientService AuthService
<PageTitle>Callback page</PageTitle>


<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
private int currentCount = 0;

private void IncrementCount()
{
currentCount++;
}
protected override async Task OnInitializedAsync()
{
string url = NavigationMgr.Uri;

//code is the only parameter in the url
string code = url.Split("=")[1];

string redirectURI = "https://localhost:44342/"; //ovo promeni da se storuje negde na neko univerzalno mesto
var response = await AuthService.GetAccessToken(new GrpcShared.DTO.Auth.TokenRequest { code = code, redirect_uri = redirectURI});

//store access token in local storage

}
}

+ 0
- 18
NemAnCore/Pages/Counter.razor Просмотреть файл

@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
private int currentCount = 0;

private void IncrementCount()
{
currentCount++;
}
}

+ 2
- 4
NemAnCore/Pages/Index.razor Просмотреть файл

protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
//var response = await SearchService.GetListSearchAsync(new GrpcShared.DTO.Search.SearchRequest() { Query="venom", Type = "track"}); //var response = await SearchService.GetListSearchAsync(new GrpcShared.DTO.Search.SearchRequest() { Query="venom", Type = "track"});
AuthParams authParams = await AuthService.GetAuthParams();
CodeRequest authParams = await AuthService.GetAuthParams();
// await AuthService.GetAccessToken(new CodeResponse{ Code = "hello"}); // await AuthService.GetAccessToken(new CodeResponse{ Code = "hello"});
AuthRequest request = new() { ResponseType = "code", Scope = authParams.Scope, ClientId = authParams.ClientId, RedirectURI = authParams.RedirectURI};
string url = $"https://accounts.spotify.com/en/authorize?client_id={request.ClientId}&redirect_uri={request.RedirectURI}&response_type={request.ResponseType}&scope={request.Scope}&show_dialog=true";

string url = $"https://accounts.spotify.com/en/authorize?client_id={authParams.ClientId}&redirect_uri={authParams.RedirectURI}&response_type={authParams.ResponseType}&scope={authParams.Scope}&show_dialog={authParams.ShowDialog}";


NavigationManager.NavigateTo(url); NavigationManager.NavigateTo(url);
} }

+ 4
- 8
NemAnCore/Services/AuthClientService.cs Просмотреть файл

{ {
_serviceClient = grpcChannel.CreateGrpcService<IAuthService>(); _serviceClient = grpcChannel.CreateGrpcService<IAuthService>();
} }
public async Task<AuthResponse> GetAccessToken(CodeResponse code)
public async Task<TokenResponse> GetAccessToken(TokenRequest request)
{ {
return await _serviceClient.GetAccessToken(code);
return await _serviceClient.GetAccessToken(request);
} }


public async Task <AuthParams> GetAuthParams()
public async Task<CodeRequest> GetAuthParams()
{ {
return await _serviceClient.GetAuthParams(); return await _serviceClient.GetAuthParams();
} }

public Task<CodeResponse> GetCode(AuthRequest request)
{
throw new NotImplementedException();
}
} }
} }

+ 2
- 3
NemAnCore/Services/Interfaces/IAuthClientService.cs Просмотреть файл

{ {
public interface IAuthClientService public interface IAuthClientService
{ {
Task<CodeResponse> GetCode(AuthRequest request);
Task<AuthResponse> GetAccessToken(CodeResponse code);
Task<AuthParams> GetAuthParams();
Task<TokenResponse> GetAccessToken(TokenRequest tokenRequest);
Task<CodeRequest> GetAuthParams();
} }
} }

+ 1
- 1
NemAnCore/Shared/NavMenu.razor Просмотреть файл

</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<NavLink class="nav-link" href="callback">
<span class="oi oi-plus" aria-hidden="true"></span> Counter <span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink> </NavLink>
</div> </div>

+ 1
- 0
NemAnCore/_Imports.razor Просмотреть файл

@using Microsoft.JSInterop @using Microsoft.JSInterop
@using NemAnBlazor @using NemAnBlazor
@using NemAnBlazor.Shared @using NemAnBlazor.Shared
@using System.Web

Загрузка…
Отмена
Сохранить