| using ProtoBuf; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace GrpcShared.DTO | |||||
| { | |||||
| [ProtoContract] | |||||
| public class TokenMessage | |||||
| { | |||||
| [ProtoMember(1)] | |||||
| public string? Token { get; set; } | |||||
| } | |||||
| } |
| using ProtoBuf; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace GrpcShared.DTO.User | |||||
| { | |||||
| [ProtoContract] | |||||
| public class UserInfoResponse | |||||
| { | |||||
| [ProtoMember(1)] | |||||
| public string? email { get; set; } | |||||
| [ProtoMember(2)] | |||||
| public string? id { get; set; } | |||||
| [ProtoMember(3)] | |||||
| public string? display_name { get; set; } | |||||
| } | |||||
| } |
| </PropertyGroup> | </PropertyGroup> | ||||
| <ItemGroup> | <ItemGroup> | ||||
| <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" /> | |||||
| <PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" /> | <PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" /> | ||||
| <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> | |||||
| <PackageReference Include="protobuf-net.BuildTools" Version="3.1.17"> | <PackageReference Include="protobuf-net.BuildTools" Version="3.1.17"> | ||||
| <PrivateAssets>all</PrivateAssets> | <PrivateAssets>all</PrivateAssets> | ||||
| <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
| using GrpcShared.DTO.Auth; | |||||
| using GrpcShared.DTO; | |||||
| using GrpcShared.DTO.Auth; | |||||
| using GrpcShared.DTO.User; | |||||
| using ProtoBuf.Grpc.Configuration; | using ProtoBuf.Grpc.Configuration; | ||||
| namespace GrpcShared.Interfaces | namespace GrpcShared.Interfaces | ||||
| { | { | ||||
| Task<TokenResponse> GetAccessToken(TokenRequest code); | Task<TokenResponse> GetAccessToken(TokenRequest code); | ||||
| Task<CodeRequest> GetAuthParams(); | Task<CodeRequest> GetAuthParams(); | ||||
| Task<UserInfoResponse> GetUserInfo(TokenMessage token); | |||||
| //Task<ClientSecrets> GetClientSecrets(); | //Task<ClientSecrets> GetClientSecrets(); | ||||
| } | } | ||||
| } | } |
| <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" /> | ||||
| <PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" /> | <PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" /> | ||||
| <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.22.0" /> | |||||
| </ItemGroup> | </ItemGroup> | ||||
| <ItemGroup> | <ItemGroup> |
| using Microsoft.Extensions.Options; | using Microsoft.Extensions.Options; | ||||
| using GrpcShared.DTO.Auth; | using GrpcShared.DTO.Auth; | ||||
| using SpotifyService.Services; | using SpotifyService.Services; | ||||
| using Blazored.SessionStorage; | |||||
| var builder = WebApplication.CreateBuilder(args); | var builder = WebApplication.CreateBuilder(args); | ||||
| #if DEBUG | #if DEBUG | ||||
| builder.Services.AddGrpc(); | builder.Services.AddGrpc(); | ||||
| builder.Services.AddCodeFirstGrpc(); | builder.Services.AddCodeFirstGrpc(); | ||||
| builder.Services.AddCodeFirstGrpcReflection(); | builder.Services.AddCodeFirstGrpcReflection(); | ||||
| builder.Services.AddBlazoredSessionStorage(); | |||||
| //call spotify api | //call spotify api | ||||
| builder.Services.AddHttpClient(); | builder.Services.AddHttpClient(); | ||||
| //using IdentityProvider.Protos.AuthService; | //using IdentityProvider.Protos.AuthService; | ||||
| using Blazored.SessionStorage; | |||||
| using Grpc.Net.Client; | using Grpc.Net.Client; | ||||
| using GrpcShared; | using GrpcShared; | ||||
| using GrpcShared.DTO; | |||||
| using GrpcShared.DTO.Auth; | using GrpcShared.DTO.Auth; | ||||
| using GrpcShared.DTO.User; | |||||
| using GrpcShared.Interfaces; | using GrpcShared.Interfaces; | ||||
| using Microsoft.Extensions.Options; | using Microsoft.Extensions.Options; | ||||
| using Microsoft.Net.Http.Headers; | using Microsoft.Net.Http.Headers; | ||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| using System.Diagnostics; | |||||
| using System.IdentityModel.Tokens.Jwt; | |||||
| using System.IO; | |||||
| using System.Net.Http.Headers; | using System.Net.Http.Headers; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Text.Json; | using System.Text.Json; | ||||
| private readonly ILogger<AuthService> _logger; | private readonly ILogger<AuthService> _logger; | ||||
| private readonly CodeRequest _params; | private readonly CodeRequest _params; | ||||
| private readonly IHttpClientFactory _httpClientFactory; | private readonly IHttpClientFactory _httpClientFactory; | ||||
| //private ISessionStorageService _sessionStorageService; | |||||
| public AuthService(ILogger<AuthService> logger, IOptions<CodeRequest> options, IHttpClientFactory httpClientFactory) | public AuthService(ILogger<AuthService> logger, IOptions<CodeRequest> options, IHttpClientFactory httpClientFactory) | ||||
| { | { | ||||
| _logger = logger; | _logger = logger; | ||||
| return await Task.FromResult(authParams); | return await Task.FromResult(authParams); | ||||
| } | } | ||||
| public async Task<UserInfoResponse> GetUserInfo(TokenMessage tokenM) | |||||
| { | |||||
| //var des = JsonConvert.DeserializeObject<TokenMessage>(tokenM); | |||||
| //var tokenStorage = _sessionStorageService.GetItemAsync<string>("token"); | |||||
| //hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken); | |||||
| //var response = hc.GetAsync(userInfoUrl).Result; | |||||
| //dynamic userInfo = response.Content.ReadAsAsync().Result; | |||||
| //return userInfo; | |||||
| var http = _httpClientFactory.CreateClient(); | |||||
| http.BaseAddress = new Uri("https://api.spotify.com/v1/me"); | |||||
| http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenM.Token); | |||||
| var response = http.GetAsync(http.BaseAddress).Result; | |||||
| var userInfo = JsonConvert.DeserializeObject<UserInfoResponse>(await response.Content.ReadAsStringAsync())!; | |||||
| return userInfo; | |||||
| //http.DefaultRequestHeaders.Add(HeaderNames.Authorization, "Bearer " + token.Token); | |||||
| //var response = await http.GetAsync(http.BaseAddress + "me"); | |||||
| //var user = JsonConvert.DeserializeObject<UserInfoResponse>(await response.Content.ReadAsStringAsync()); | |||||
| //return await Task.FromResult(user!); | |||||
| } | |||||
| } | } | ||||
| } | } |
| "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 user-read-private", | |||||
| "ClientSecret": "ea752433d0774fad87fab5c1ee788c8d" | "ClientSecret": "ea752433d0774fad87fab5c1ee788c8d" | ||||
| } | } | ||||
| } | } |
| <PackageReference Include="Blazored.SessionStorage" Version="2.2.0" /> | <PackageReference Include="Blazored.SessionStorage" Version="2.2.0" /> | ||||
| <PackageReference Include="Grpc.Net.Client" Version="2.47.0" /> | <PackageReference Include="Grpc.Net.Client" Version="2.47.0" /> | ||||
| <PackageReference Include="Grpc.Net.Client.Web" Version="2.47.0" /> | <PackageReference Include="Grpc.Net.Client.Web" Version="2.47.0" /> | ||||
| <PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.8" /> | |||||
| <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.7" /> | <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.7" /> | ||||
| <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.7" PrivateAssets="all" /> | <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.7" PrivateAssets="all" /> | ||||
| <PackageReference Include="protobuf-net.Grpc" Version="1.0.171" /> | <PackageReference Include="protobuf-net.Grpc" Version="1.0.171" /> |
| @page "/search" | @page "/search" | ||||
| @using Grpc.Core | |||||
| @using GrpcShared.DTO | |||||
| @using GrpcShared.DTO.Search | @using GrpcShared.DTO.Search | ||||
| @using GrpcShared.DTO.Track.MultipleTrack | @using GrpcShared.DTO.Track.MultipleTrack | ||||
| @using GrpcShared.DTO.Track.SingleTrack | @using GrpcShared.DTO.Track.SingleTrack | ||||
| @using NemAnBlazor.Services.Interfaces | @using NemAnBlazor.Services.Interfaces | ||||
| @using System.Diagnostics | |||||
| @*@inject HttpClient Http*@ | @*@inject HttpClient Http*@ | ||||
| @inject Blazored.SessionStorage.ISessionStorageService sessionStorage | @inject Blazored.SessionStorage.ISessionStorageService sessionStorage | ||||
| @inject ITrackClientService SearchService | @inject ITrackClientService SearchService | ||||
| @inject IAuthClientService AuthService | |||||
| <PageTitle>Search</PageTitle> | <PageTitle>Search</PageTitle> | ||||
| <h1>Search</h1> | <h1>Search</h1> | ||||
| <button class="btn btn-primary" @onclick="Click">Click me</button> | |||||
| @code { | @code { | ||||
| protected override async Task OnInitializedAsync() | protected override async Task OnInitializedAsync() | ||||
| { | { | ||||
| var token = await sessionStorage.GetItemAsync<string>("token"); | |||||
| //SearchRequest request = new() { Query = "aitch", Type = "track", Token = token }; | |||||
| //SearchResponse searchResponse = await SearchService.GetListSearchAsync(request); | |||||
| MultipleTrackRequest mreq = new() { Ids = new List<string>(){"3JAeYOjyJodI4PRs44lx2l", "6clZa1yrZe7pJrYFUcD9KW"}, Token = token }; | |||||
| MultipleTrackResponse multipleTrackResponse = await SearchService.GetListMultipleTrackAsync(mreq); | |||||
| //MultipleTrackRequest mreq = new() { Ids = new List<string>(){"3JAeYOjyJodI4PRs44lx2l", "6clZa1yrZe7pJrYFUcD9KW"}, Token = token }; | |||||
| //MultipleTrackResponse multipleTrackResponse = await SearchService.GetListMultipleTrackAsync(mreq); | |||||
| //SingleTrackRequest singleTrackRequest = new() { Id = "3JAeYOjyJodI4PRs44lx2l", Token = token }; | //SingleTrackRequest singleTrackRequest = new() { Id = "3JAeYOjyJodI4PRs44lx2l", Token = token }; | ||||
| //SingleTrackResponse singleTrackResponse = await SearchService.GetListSingleTrackAsync(singleTrackRequest); | //SingleTrackResponse singleTrackResponse = await SearchService.GetListSingleTrackAsync(singleTrackRequest); | ||||
| } | } | ||||
| private async Task Click(){ | |||||
| var token = await sessionStorage.GetItemAsync<string>("token"); | |||||
| TokenMessage tm = new() { Token = token }; | |||||
| if ((await AuthService.GetUserInfo(tm)) != null) | |||||
| { | |||||
| SearchRequest request = new() { Query = "aitch", Type = "track", Token = token }; | |||||
| SearchResponse searchResponse = await SearchService.GetListSearchAsync(request); | |||||
| } | |||||
| } | |||||
| } | } |
| using NemAnBlazor.Services.Interfaces; | using NemAnBlazor.Services.Interfaces; | ||||
| using ProtoBuf.Grpc.Client; | using ProtoBuf.Grpc.Client; | ||||
| using GrpcShared; | using GrpcShared; | ||||
| using GrpcShared.DTO.User; | |||||
| using GrpcShared.DTO; | |||||
| using System.Security.Claims; | |||||
| using Microsoft.AspNetCore.Components.Authorization; | |||||
| using Blazored.SessionStorage; | |||||
| namespace NemAnBlazor.Services | namespace NemAnBlazor.Services | ||||
| { | { | ||||
| { | { | ||||
| return await _serviceClient.GetAuthParams(); | return await _serviceClient.GetAuthParams(); | ||||
| } | } | ||||
| public async Task<UserInfoResponse> GetUserInfo(TokenMessage token) | |||||
| { | |||||
| return await _serviceClient.GetUserInfo(token); | |||||
| } | |||||
| //public override async Task<AuthenticationState> GetAuthenticationStateAsync() | |||||
| //{ | |||||
| // string token = await _sessionStorage.GetItemAsync<string>("token"); | |||||
| // //token = "BQBMgFm6jnFNWWeZEMGIRP_f-ENPid7Kw8JubAyuWAe4JK0S1DPFGlaAdZ_Fey6ePkCnz8-cqC0oyRmrciWUy5ISUTQKDe8PTQn4iBRMYCgM0n4GnS1xAErHJcm4Vpu2TAngk-4vQUOfTQRcedNTfCaHKP4uFJgTlTI7JHGrtB-_EZLnFcZ2OQe31oFQIJ1wM3ZtvwnN"; | |||||
| // if (token == null) return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); | |||||
| // var userInfo = await _serviceClient.GetUserInfo(new TokenMessage { Token = token }); | |||||
| // List<Claim> claims = new(); | |||||
| // claims.Add(new Claim("email", userInfo.email!)); | |||||
| // claims.Add(new Claim("id", userInfo.id!)); | |||||
| // claims.Add(new Claim("name", userInfo.display_name!)); | |||||
| // ClaimsIdentity identity = new(claims, "jwt"); | |||||
| // //ClaimsIdentity identity = new(); | |||||
| // ClaimsPrincipal user = new(identity); | |||||
| // AuthenticationState state = new(user); | |||||
| // NotifyAuthenticationStateChanged(Task.FromResult(state)); | |||||
| // return state; | |||||
| //} | |||||
| } | } | ||||
| } | } |
| using GrpcShared; | using GrpcShared; | ||||
| using GrpcShared.DTO; | |||||
| using GrpcShared.DTO.Auth; | using GrpcShared.DTO.Auth; | ||||
| using GrpcShared.DTO.User; | |||||
| namespace NemAnBlazor.Services.Interfaces | namespace NemAnBlazor.Services.Interfaces | ||||
| { | { | ||||
| { | { | ||||
| Task<TokenResponse> GetAccessToken(TokenRequest tokenRequest); | Task<TokenResponse> GetAccessToken(TokenRequest tokenRequest); | ||||
| Task<CodeRequest> GetAuthParams(); | Task<CodeRequest> GetAuthParams(); | ||||
| Task<UserInfoResponse> GetUserInfo(TokenMessage token); | |||||
| } | } | ||||
| } | } |
| using Microsoft.AspNetCore.Server.Kestrel.Core; | using Microsoft.AspNetCore.Server.Kestrel.Core; | ||||
| using NemAnBlazor.Services.Interfaces; | |||||
| using NemAnBlazor.Services; | |||||
| using ProtoBuf.Grpc.Server; | using ProtoBuf.Grpc.Server; | ||||
| using SpotifyService.Services; | using SpotifyService.Services; | ||||
| using GrpcShared.Interfaces; | |||||
| using Polly; | |||||
| using Polly.Extensions.Http; | |||||
| var builder = WebApplication.CreateBuilder(args); | var builder = WebApplication.CreateBuilder(args); | ||||
| { | { | ||||
| c.BaseAddress = new Uri(SpotifyService.GLOBALS.SPOTIFYURL); | c.BaseAddress = new Uri(SpotifyService.GLOBALS.SPOTIFYURL); | ||||
| c.DefaultRequestHeaders.Add("Accept", SpotifyService.GLOBALS.MEDIATYPE); | c.DefaultRequestHeaders.Add("Accept", SpotifyService.GLOBALS.MEDIATYPE); | ||||
| }); | |||||
| }) | |||||
| .SetHandlerLifetime(TimeSpan.FromMinutes(5)) | |||||
| .AddPolicyHandler(GetRetryPolicy()) | |||||
| .AddPolicyHandler(GetCircuitBreaker()); | |||||
| IAsyncPolicy<HttpResponseMessage> GetCircuitBreaker() | |||||
| { | |||||
| return HttpPolicyExtensions | |||||
| .HandleTransientHttpError() | |||||
| //the circuit will be cut if 25% of requests fail in a 60 second window, with a minimum of 7 requests in the 60 second window, | |||||
| //then the circuit should be cut for 30 seconds: | |||||
| .AdvancedCircuitBreakerAsync(0.25, TimeSpan.FromSeconds(60), | |||||
| 7, TimeSpan.FromSeconds(30), OnBreak, OnReset, OnHalfOpen); | |||||
| } | |||||
| void OnHalfOpen() | |||||
| { | |||||
| Console.WriteLine("Circuit in test mode, one request will be allowed."); | |||||
| } | |||||
| void OnReset() | |||||
| { | |||||
| Console.WriteLine("Circuit closed, requests flow normally."); | |||||
| } | |||||
| void OnBreak(DelegateResult<HttpResponseMessage> result, TimeSpan ts) | |||||
| { | |||||
| Console.WriteLine("Circuit cut, requests will not flow."); | |||||
| } | |||||
| IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() | |||||
| { | |||||
| return HttpPolicyExtensions | |||||
| // HttpRequestException, 5XX and 408 | |||||
| .HandleTransientHttpError() | |||||
| // 404 | |||||
| .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) | |||||
| // Retry two times after delay | |||||
| .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(3, retryAttempt))); | |||||
| } | |||||
| builder.Services.AddControllersWithViews(); | builder.Services.AddControllersWithViews(); | ||||
| builder.Services.AddRazorPages(); | builder.Services.AddRazorPages(); | ||||
| app.MapRazorPages(); | app.MapRazorPages(); | ||||
| app.MapControllers(); | app.MapControllers(); | ||||
| //app.MapGrpcService<WeatherService>(); | |||||
| //app.MapGrpcService<SearchService>().EnableGrpcWeb(); | |||||
| //app.MapGrpcService<AuthService>(); | |||||
| //app.MapGrpcService<AuthService>().EnableGrpcWeb(); | |||||
| app.MapCodeFirstGrpcReflectionService(); | app.MapCodeFirstGrpcReflectionService(); | ||||
| using Grpc.Core; | |||||
| using Google.Rpc; | |||||
| using Grpc.Core; | |||||
| using GrpcShared; | using GrpcShared; | ||||
| using GrpcShared.DTO.Search; | using GrpcShared.DTO.Search; | ||||
| using GrpcShared.DTO.Track.MultipleTrack; | using GrpcShared.DTO.Track.MultipleTrack; | ||||
| using GrpcShared.DTO.Track.SaveTracks; | using GrpcShared.DTO.Track.SaveTracks; | ||||
| using GrpcShared.DTO.Track.SingleTrack; | using GrpcShared.DTO.Track.SingleTrack; | ||||
| using GrpcShared.Interfaces; | using GrpcShared.Interfaces; | ||||
| using Microsoft.AspNetCore.Authorization; | |||||
| using Microsoft.Net.Http.Headers; | using Microsoft.Net.Http.Headers; | ||||
| using NemAnBlazor.Services; | |||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Text.Json; | using System.Text.Json; | ||||
| public class TrackService : ITrackService | public class TrackService : ITrackService | ||||
| { | { | ||||
| private readonly IHttpClientFactory _httpClientFactory; | private readonly IHttpClientFactory _httpClientFactory; | ||||
| public TrackService(IHttpClientFactory httpClientFactory) | public TrackService(IHttpClientFactory httpClientFactory) | ||||
| { | { | ||||
| _httpClientFactory = httpClientFactory; | _httpClientFactory = httpClientFactory; | ||||
| } | } | ||||
| public async Task<SearchResponse> ListSearchAsync(SearchRequest request) | public async Task<SearchResponse> ListSearchAsync(SearchRequest request) | ||||
| { | { | ||||
| var client = _httpClientFactory.CreateClient("HttpClient"); | var client = _httpClientFactory.CreateClient("HttpClient"); | ||||
| client.DefaultRequestHeaders.Add(HeaderNames.Authorization, "Bearer " + request.Token ); | client.DefaultRequestHeaders.Add(HeaderNames.Authorization, "Bearer " + request.Token ); |
| </PropertyGroup> | </PropertyGroup> | ||||
| <ItemGroup> | <ItemGroup> | ||||
| <PackageReference Include="Google.Api.CommonProtos" Version="2.6.0" /> | |||||
| <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="Microsoft.Extensions.Http.Polly" Version="6.0.8" /> | |||||
| <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> | <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> | ||||
| <PackageReference Include="Polly" Version="7.2.3" /> | |||||
| <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" /> |