瀏覽代碼

Merge branch 'feature/auth-flow' into dev

tags/v1.1.0^2
anastasijasavov 3 年之前
父節點
當前提交
b6b92c3392

+ 0
- 131
Grpc.Shared/DTOs/Search/SearchDTO.cs 查看文件

@@ -1,131 +0,0 @@
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace Grpc.Shared.DTOs.Search
{
[ProtoContract]
internal class SearchDTO
{
public partial class SearchContracts
{
[ProtoMember(1)]
public Tracks? Tracks { get; set; }
}

public partial class Tracks
{
[ProtoMember(1)]
public Uri Href { get; set; }

[ProtoMember(2)]
public Items[]? Items { get; set; }
}

public partial class Items
{
[ProtoMember(1)]
public Album Album { get; set; }

[ProtoMember(2)]
public Artist[] Artists { get; set; }

[ProtoMember(3)]
public long DurationMs { get; set; }

[ProtoMember(4)]
public ExternalUrls ExternalUrls { get; set; }

[ProtoMember(5)]
public Uri Href { get; set; }

[ProtoMember(6)]
public string Id { get; set; }

[ProtoMember(7)]
public string Name { get; set; }

[ProtoMember(8)]
public long Popularity { get; set; }

[ProtoMember(9)]
public long TrackNumber { get; set; }

[ProtoMember(10)]
public string Type { get; set; }

[ProtoMember(11)]
public string Uri { get; set; }
}

public partial class Album
{
[ProtoMember(1)]
public Uri Href { get; set; }

[ProtoMember(2)]
public string Id { get; set; }

[ProtoMember(3)]
public Image[] Images { get; set; }

[ProtoMember(4)]
public string Name { get; set; }

[ProtoMember(5)]
public DateTimeOffset ReleaseDate { get; set; }

[ProtoMember(6)]
public long TotalTracks { get; set; }

[ProtoMember(7)]
public string Type { get; set; }

[ProtoMember(8)]
public string Uri { get; set; }
}

public partial class Image
{
[ProtoMember(1)]
public long Height { get; set; }

[ProtoMember(2)]
public Uri Url { get; set; }

[ProtoMember(3)]
public long Width { get; set; }
}

public partial class Artist
{
[ProtoMember(1)]
public ExternalUrls ExternalUrls { get; set; }

[ProtoMember(2)]
public Uri Href { get; set; }

[ProtoMember(3)]
public string Id { get; set; }

[ProtoMember(4)]
public string Name { get; set; }

[ProtoMember(5)]
public string Type { get; set; }

[ProtoMember(6)]
public string Uri { get; set; }
}

public partial class ExternalUrls
{
[ProtoMember(1)]
public Uri Spotify { get; set; }
}
}
}

+ 0
- 14
Grpc.Shared/DTOs/Search/SearchRequestDTO.cs 查看文件

@@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Grpc.Shared.DTOs.Search
{
internal class SearchRequestDTO
{

}

}

+ 0
- 14
Grpc.Shared/GrpcShared.csproj 查看文件

@@ -1,14 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="protobuf-net.Core" Version="3.1.17" />
<PackageReference Include="System.ServiceModel.Primitives" Version="4.5.3" />
</ItemGroup>

</Project>

+ 0
- 34
Grpc.Shared/Interfaces/ISearchService.cs 查看文件

@@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace GrpcShared.Interfaces
{
[ServiceContract]
public interface ISearchService
{
Task<SearchResult> SearchTracks(SearchRequest req);
}

[DataContract]
public class SearchResult
{
[DataMember(Order = 1)]
public string NewQuery { get; set; }
[DataMember(Order = 2)]
public string NewType { get; set; }
}

[DataContract]
public class SearchRequest
{
[DataMember(Order = 1)]
public string Query { get; set; }
[DataMember(Order = 2)]
public string Type { get; set; } = "track";
}
}

+ 0
- 16
GrpcShared/DTO/Auth/AuthParams.cs 查看文件

@@ -1,16 +0,0 @@
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 查看文件

@@ -1,26 +0,0 @@
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 查看文件

@@ -0,0 +1,28 @@
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 查看文件

@@ -1,16 +0,0 @@
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 查看文件

@@ -0,0 +1,22 @@
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 查看文件

@@ -8,11 +8,13 @@ using System.Threading.Tasks;
namespace GrpcShared.DTO.Auth
{
[ProtoContract]
public class AuthResponse
public class TokenResponse
{
[ProtoMember(1)]
public string AccessToken { get; set; }
public string? access_token { get; set; }
[ProtoMember(2)]
public string RefreshToken{ get; set; }
public string? refresh_token{ get; set; }
[ProtoMember(3)]
public int? expires_in { get; set; }
}
}

+ 3
- 3
GrpcShared/Interfaces/IAuthService.cs 查看文件

@@ -6,8 +6,8 @@ namespace GrpcShared.Interfaces
[Service]
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 查看文件

@@ -10,6 +10,7 @@
<PackageReference Include="Grpc.AspNetCore" Version="2.40.0" />
<PackageReference Include="Grpc.AspNetCore.Web" Version="2.47.0" />
<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.AspNetCore" Version="1.0.152" />
<PackageReference Include="protobuf-net.Grpc.AspNetCore.Reflection" Version="1.0.152" />

+ 6
- 1
IdentityProvider/Program.cs 查看文件

@@ -3,6 +3,7 @@ using IdentityProvider.Services;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using ProtoBuf.Grpc.Server;
using Microsoft.Extensions.Options;
using GrpcShared.DTO.Auth;

var builder = WebApplication.CreateBuilder(args);
#if DEBUG
@@ -20,7 +21,7 @@ builder.WebHost.ConfigureKestrel(options =>
builder.Services.AddOptions();
// 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
builder.Services.Configure<AuthParams>(builder.Configuration.GetSection("AuthParams"));
builder.Services.Configure<CodeRequest>(builder.Configuration.GetSection("AuthParams"));
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

@@ -29,6 +30,8 @@ builder.Services.AddEndpointsApiExplorer();
builder.Services.AddGrpc();
builder.Services.AddCodeFirstGrpc();
builder.Services.AddCodeFirstGrpcReflection();
//call spotify api
builder.Services.AddHttpClient();

var app = builder.Build();

@@ -46,11 +49,13 @@ else

app.UseHttpsRedirection();

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

app.UseRouting();

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

app.MapRazorPages();

+ 50
- 11
IdentityProvider/Services/AuthService.cs 查看文件

@@ -1,39 +1,78 @@
//using IdentityProvider.Protos.AuthService;
using Grpc.Net.Client;
using GrpcShared;
using GrpcShared.DTO.Auth;
using GrpcShared.Interfaces;
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
{
public class AuthService : IAuthService
{
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;
_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, and redirect uri from appsettings, convert to base64 and set as header
var secrets = await GetAuthParams();
byte[] contentType = Encoding.UTF8.GetBytes($"{secrets.ClientId}:{secrets.ClientSecret}");
tokenRequest.redirect_uri = secrets.RedirectURI;

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

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

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

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

var contents = JsonConvert.DeserializeObject<TokenResponse>(await response.Content.ReadAsStringAsync());
return new TokenResponse
{
access_token = contents!.access_token,
refresh_token = contents!.refresh_token,
expires_in = contents!.expires_in
};
}

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

}
}

+ 2
- 1
IdentityProvider/appsettings.json 查看文件

@@ -14,6 +14,7 @@
"AuthParams": {
"ClientId": "83e1d09876b049c4bb1953185a4b3bfb",
"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"
}
}

+ 1
- 0
NemAnCore/NemAnBlazor.csproj 查看文件

@@ -7,6 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Blazored.SessionStorage" Version="2.2.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.47.0" />
<PackageReference Include="Grpc.Net.Client.Web" Version="2.47.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.7" />

+ 37
- 0
NemAnCore/Pages/Callback.razor 查看文件

@@ -0,0 +1,37 @@
@page "/callback"
@using NemAnBlazor.Services.Interfaces
@inject NavigationManager NavigationMgr
@inject IAuthClientService AuthService
@inject Blazored.SessionStorage.ISessionStorageService sessionStorage
<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];

var response = await AuthService.GetAccessToken(new GrpcShared.DTO.Auth.TokenRequest { code = code});


//store access token in local storage
await sessionStorage.SetItemAsync("token", response.access_token);
await sessionStorage.SetItemAsync("refresh_token", response.refresh_token);

//redirect to home
NavigationMgr.NavigateTo("/home");
}
}

+ 0
- 18
NemAnCore/Pages/Counter.razor 查看文件

@@ -1,18 +0,0 @@
@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++;
}
}

+ 7
- 0
NemAnCore/Pages/Home.razor 查看文件

@@ -0,0 +1,7 @@
@page "/home"
<h3>Home</h3>

<p>pozdrav, login radi</p>
@code {

}

+ 2
- 4
NemAnCore/Pages/Index.razor 查看文件

@@ -19,11 +19,9 @@ Dobrodošli u našu NemAn aplikaciju.
protected override async Task OnInitializedAsync()
{
//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"});
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);
}

+ 2
- 0
NemAnCore/Program.cs 查看文件

@@ -1,3 +1,4 @@
using Blazored.SessionStorage;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
using Microsoft.AspNetCore.Components;
@@ -23,6 +24,7 @@ builder.Services.AddScoped(_ =>

builder.Services.AddScoped<ISearchClientService, SearchClientService>();
builder.Services.AddScoped<IAuthClientService, AuthClientService>();
builder.Services.AddBlazoredSessionStorage();

await builder.Build().RunAsync();


+ 4
- 8
NemAnCore/Services/AuthClientService.cs 查看文件

@@ -15,19 +15,15 @@ namespace NemAnBlazor.Services
{
_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();
}

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

+ 2
- 3
NemAnCore/Services/Interfaces/IAuthClientService.cs 查看文件

@@ -5,8 +5,7 @@ namespace NemAnBlazor.Services.Interfaces
{
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 查看文件

@@ -15,7 +15,7 @@
</NavLink>
</div>
<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
</NavLink>
</div>

+ 1
- 0
NemAnCore/_Imports.razor 查看文件

@@ -8,3 +8,4 @@
@using Microsoft.JSInterop
@using NemAnBlazor
@using NemAnBlazor.Shared
@using System.Web

Loading…
取消
儲存