| @@ -14,5 +14,7 @@ namespace GrpcShared.DTO.Db | |||
| public string Id { get; set; } | |||
| [ProtoMember(2)] | |||
| public string Token { get; set; } | |||
| [ProtoMember(3)] | |||
| public string RefreshToken{ get; set; } | |||
| } | |||
| } | |||
| @@ -10,5 +10,8 @@ namespace GrpcShared.DTO | |||
| [ProtoContract] | |||
| public class VoidMessage | |||
| { | |||
| [ProtoMember(1)] | |||
| public string InsertedId { get; set; } | |||
| } | |||
| } | |||
| @@ -19,5 +19,6 @@ namespace GrpcShared.Interfaces | |||
| Task<VoidMessage> DeleteTrackAsync(DbRequestMessage id); | |||
| Task<VoidMessage> SaveUserAsync(UserResponse user); | |||
| Task<VoidMessage> DeleteUserAsync(DbRequestMessage user); | |||
| Task<VoidMessage> UpdateTokenAsync (UserResponse user); | |||
| } | |||
| } | |||
| @@ -9,5 +9,6 @@ namespace IdentityProvider.Models | |||
| [BsonRepresentation(BsonType.ObjectId)] | |||
| public string Id { get; set; } | |||
| public string Token { get; set; } | |||
| public string RefreshToken { get; set; } | |||
| } | |||
| } | |||
| @@ -1,4 +1,4 @@ | |||
| { | |||
| { | |||
| "iisSettings": { | |||
| "windowsAuthentication": false, | |||
| "anonymousAuthentication": true, | |||
| @@ -10,21 +10,20 @@ | |||
| "profiles": { | |||
| "IIS Express": { | |||
| "commandName": "IISExpress", | |||
| "launchBrowser": true, | |||
| "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", | |||
| "environmentVariables": { | |||
| "ASPNETCORE_ENVIRONMENT": "Development" | |||
| } | |||
| }, | |||
| "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}" | |||
| }, | |||
| "IdentityProvider": { | |||
| "commandName": "Project", | |||
| "dotnetRunMessages": "true", | |||
| "launchBrowser": true, | |||
| "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", | |||
| "applicationUrl": "https://localhost:5001;http://localhost:5000", | |||
| "environmentVariables": { | |||
| "ASPNETCORE_ENVIRONMENT": "Development" | |||
| } | |||
| }, | |||
| "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", | |||
| "applicationUrl": "https://localhost:5001;http://localhost:5000", | |||
| "dotnetRunMessages": "true" | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -34,11 +34,13 @@ namespace IdentityProvider.Services | |||
| public async Task<UserResponse> GetTokenByIdAsync(DbRequestMessage request) | |||
| { | |||
| UserModel user = await _userCollection.Find(u => u.Id == request.Id).FirstOrDefaultAsync(); | |||
| return new UserResponse | |||
| { | |||
| Id = user.Id, | |||
| Token = user.Token | |||
| }; | |||
| if (user != null) | |||
| return new UserResponse | |||
| { | |||
| Id = user.Id, | |||
| Token = user.Token | |||
| }; | |||
| else return new UserResponse(); | |||
| } | |||
| public async Task<TrackResponse> GetTrackByUserAsync(DbRequestMessage request) | |||
| { | |||
| @@ -57,6 +59,7 @@ namespace IdentityProvider.Services | |||
| TrackModel trackModel = new() | |||
| { | |||
| Id = track.Id, | |||
| Title = track.Title, | |||
| Album = track.Album, | |||
| Artist = track.Artist, | |||
| @@ -64,24 +67,30 @@ namespace IdentityProvider.Services | |||
| TrackId = track.TrackId | |||
| }; | |||
| //first check if there's already a song in the db, if yes, update the row | |||
| var song = await _trackCollection.Find(x => x.UserId == track.UserId).AnyAsync(); | |||
| bool song = await _trackCollection.Find(x => x.UserId == track.UserId).AnyAsync(); | |||
| if (song) await _trackCollection.ReplaceOneAsync(x => x.UserId == track.UserId, trackModel); | |||
| if (song) await _trackCollection.DeleteOneAsync(s => s.UserId == track.UserId); | |||
| else await _trackCollection.InsertOneAsync(trackModel); | |||
| await _trackCollection.InsertOneAsync(trackModel); | |||
| return new VoidMessage(); | |||
| return new VoidMessage() { InsertedId = trackModel.Id }; | |||
| } | |||
| public async Task<VoidMessage> SaveUserAsync(UserResponse userRequest) | |||
| { | |||
| bool user = await _userCollection.Find(x => x.Id == userRequest.Id).AnyAsync(); | |||
| if (!user) await _userCollection.InsertOneAsync(new UserModel | |||
| UserModel tempUser = new() | |||
| { | |||
| Token = userRequest.Token | |||
| }); | |||
| return new VoidMessage(); | |||
| Token = userRequest.Token, | |||
| RefreshToken = userRequest.RefreshToken | |||
| }; | |||
| if (!user) await _userCollection.InsertOneAsync(tempUser); | |||
| return new VoidMessage() { InsertedId = tempUser.Id }; | |||
| } | |||
| public async Task<VoidMessage> DeleteTrackAsync(DbRequestMessage request) | |||
| { | |||
| @@ -102,7 +111,21 @@ namespace IdentityProvider.Services | |||
| return new VoidMessage(); | |||
| } | |||
| public async Task<VoidMessage> UpdateTokenAsync(UserResponse user) | |||
| { | |||
| UserModel dbUser = await _userCollection.Find(x => x.Id == user.Id).FirstOrDefaultAsync(); | |||
| if (dbUser.Id != null) | |||
| { | |||
| dbUser.Token = user.Token; | |||
| dbUser.RefreshToken = user.RefreshToken; | |||
| await _userCollection.ReplaceOneAsync(x => x.Id == user.Id, dbUser); | |||
| } | |||
| return new VoidMessage | |||
| { | |||
| InsertedId = dbUser.Id | |||
| }; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,8 +1,12 @@ | |||
| @page "/callback" | |||
| @using GrpcShared.DTO | |||
| @using GrpcShared.DTO.Db | |||
| @using NemAnBlazor.Services.Interfaces | |||
| @inject NavigationManager NavigationMgr | |||
| @inject IAuthClientService AuthService | |||
| @inject Blazored.LocalStorage.ILocalStorageService localStorage | |||
| @inject IIdentityClientService identityService | |||
| <PageTitle>Redirecting...</PageTitle> | |||
| @@ -24,9 +28,20 @@ | |||
| //if (response.access_token == null) NavigationMgr.NavigateTo("/"); | |||
| //store access token in local storage | |||
| await localStorage.SetItemAsync("token", response.AccessToken); | |||
| await localStorage.SetItemAsync("refresh_token", response.RefreshToken); | |||
| //await localStorage.SetItemAsync("token", response.AccessToken); | |||
| //await localStorage.SetItemAsync("refresh_token", response.RefreshToken); | |||
| //UserResponse user = new(); | |||
| //await identityService.SaveUserAsync(new GrpcShared.DTO.Db.UserResponse()); | |||
| string userId = await localStorage.GetItemAsync<string>("user_info"); | |||
| if(userId == null) | |||
| { | |||
| VoidMessage userRes = await identityService.SaveUserAsync(new GrpcShared.DTO.Db.UserResponse { RefreshToken = response.RefreshToken , Token = response.AccessToken}); | |||
| if (userRes.InsertedId != null) | |||
| await localStorage.SetItemAsync<string>("user_info", userRes.InsertedId); | |||
| } | |||
| //redirect to home | |||
| NavigationMgr.NavigateTo("/home"); | |||
| } | |||
| @@ -12,6 +12,7 @@ | |||
| @inject Blazored.LocalStorage.ILocalStorageService localStorage | |||
| @inject ITrackClientService SearchService | |||
| @inject IAuthClientService AuthService | |||
| @inject IIdentityClientService identityService | |||
| <PageTitle>Search</PageTitle> | |||
| @@ -35,12 +36,16 @@ | |||
| private async Task Click() | |||
| { | |||
| var token = await localStorage.GetItemAsync<string>("token"); | |||
| string refreshT = await localStorage.GetItemAsync<string>("refresh_token"); | |||
| var userInfo = await localStorage.GetItemAsync<string>("user_info"); | |||
| TokenMessage tokenM = new TokenMessage { Token = token, RefreshToken = refreshT }; | |||
| var user = await identityService.GetTokenByIdAsync(new GrpcShared.DTO.Db.DbRequestMessage | |||
| { | |||
| Id = userInfo | |||
| }); | |||
| TokenMessage tokenM = new TokenMessage { Token = user.Token, RefreshToken = user.RefreshToken }; | |||
| SearchRequest request = new() { Query = "aitch", Type = "track", Token = token }; | |||
| SearchRequest request = new() { Query = "aitch", Type = "track", Token = user.Token }; | |||
| try | |||
| { | |||
| @@ -48,8 +53,7 @@ | |||
| if (searchResponse.ResponseMsg == System.Net.HttpStatusCode.Unauthorized) | |||
| { | |||
| string? tempToken = await SpotifyHelper.TryRefreshToken(AuthService, tokenM, localStorage); | |||
| token = tempToken == null ? token : tempToken; | |||
| string? tempToken = await SpotifyHelper.TryRefreshToken(AuthService, tokenM, user, localStorage, identityService); | |||
| } | |||
| } | |||
| catch (RpcException e) | |||
| @@ -1,6 +1,7 @@ | |||
| @page "/home" | |||
| @using Grpc.Core | |||
| @using GrpcShared.DTO | |||
| @using GrpcShared.DTO.Db | |||
| @using GrpcShared.DTO.Track | |||
| @using NemAnBlazor.Services.Interfaces | |||
| @using System.Net | |||
| @@ -8,6 +9,7 @@ | |||
| @inject IStatsClientService spotifyService | |||
| @inject ITrackClientService trackService | |||
| @inject IAuthClientService AuthService | |||
| @inject NavigationManager NavigationMgr | |||
| @inject IIdentityClientService identityService | |||
| <h3>Home</h3> | |||
| @@ -18,12 +20,29 @@ | |||
| protected override async Task OnInitializedAsync() | |||
| { | |||
| CurrentTrackResponse track; | |||
| string tokenS = await localStorage.GetItemAsync<string>("token"); | |||
| string refreshT = await localStorage.GetItemAsync<string>("refresh_token"); | |||
| string tokenS = "", refreshT = ""; | |||
| string userId = await localStorage.GetItemAsync<string>("user_info"); | |||
| //tokenS = "BQBMgFm6jnFNWWeZEMGIRP_f-ENPid7Kw8JubAyuWAe4JK0S1DPFGlaAdZ_Fey6ePkCnz8-cqC0oyRmrciWUy5ISUTQKDe8PTQn4iBRMYCgM0n4GnS1xAErHJcm4Vpu2TAngk-4vQUOfTQRcedNTfCaHKP4uFJgTlTI7JHGrtB-_EZLnFcZ2OQe31oFQIJ1wM3ZtvwnN"; | |||
| TokenMessage token = new TokenMessage { Token = tokenS, RefreshToken = refreshT }; | |||
| if (userId != null) | |||
| { | |||
| //get token from identity | |||
| var userResponse = await identityService.GetTokenByIdAsync(new GrpcShared.DTO.Db.DbRequestMessage { Id = userId }); | |||
| if (userResponse != null) | |||
| { | |||
| tokenS = userResponse.Token; | |||
| refreshT = userResponse.RefreshToken; | |||
| } | |||
| else { | |||
| await localStorage.RemoveItemAsync("user_info"); | |||
| NavigationMgr.NavigateTo("/"); | |||
| } | |||
| } | |||
| //tokenS = "BQBMgFm6jnFNWWeZEMGIRP_f-ENPid7Kw8JubAyuWAe4JK0S1DPFGlaAdZ_Fey6ePkCnz8-cqC0oyRmrciWUy5ISUTQKDe8PTQn4iBRMYCgM0n4GnS1xAErHJcm4Vpu2TAngk-4vQUOfTQRcedNTfCaHKP4uFJgTlTI7JHGrtB-_EZLnFcZ2OQe31oFQIJ1wM3ZtvwnN"; | |||
| TokenMessage token = new() { Token = tokenS, RefreshToken = refreshT }; | |||
| UserResponse user = new() { Id = userId, RefreshToken = refreshT }; | |||
| try | |||
| { | |||
| track = await spotifyService.GetCurrentlyPlayingTrack(token); | |||
| @@ -31,7 +50,7 @@ | |||
| //if token expired, refresh it | |||
| if (track.ResponseMsg == System.Net.HttpStatusCode.Unauthorized) | |||
| { | |||
| string? tempToken = await SpotifyHelper.TryRefreshToken(AuthService, token, localStorage); | |||
| string? tempToken = await SpotifyHelper.TryRefreshToken(AuthService, token, user, localStorage, identityService); | |||
| tokenS = tempToken == null ? tokenS : tempToken; | |||
| //if refreshed token is null, that means that refresh token was invalid, so you should redirect to login | |||
| } | |||
| @@ -55,7 +74,7 @@ | |||
| if (items.ResponseMsg == System.Net.HttpStatusCode.Unauthorized) | |||
| { | |||
| string? tempToken = await SpotifyHelper.TryRefreshToken(AuthService, token, localStorage); | |||
| string? tempToken = await SpotifyHelper.TryRefreshToken(AuthService, token, user, localStorage, identityService); | |||
| tokenS = tempToken == null ? tokenS : tempToken; | |||
| } | |||
| } | |||
| @@ -68,10 +87,6 @@ | |||
| throw; | |||
| } | |||
| //await identityService.SaveUserAsync(new GrpcShared.DTO.Db.UserResponse | |||
| // { | |||
| // Token = tokenS | |||
| // }); | |||
| await identityService.SaveTrackAsync(new GrpcShared.DTO.Db.SaveTrackRequest | |||
| { | |||
| @@ -79,36 +94,37 @@ | |||
| Title = track.Item.Name, | |||
| Album = track.Item.Album.Name, | |||
| Artist = track.Item.Artists[0].Name, | |||
| UserId = "630748c8d149033aaf5a774a" | |||
| UserId = userId | |||
| }); | |||
| //var resp = await identityService.ListUsersAsync(new VoidMessage()); | |||
| //var tokenFromDb = await identityService.GetTokenByIdAsync(new GrpcShared.DTO.Db.DbRequestMessage | |||
| // { | |||
| // Id = "63074188426efd486fadd74d" | |||
| // }); | |||
| var tokenFromDb = await identityService.GetTokenByIdAsync(new GrpcShared.DTO.Db.DbRequestMessage | |||
| { | |||
| Id = userId | |||
| }); | |||
| //var trackByUser = await identityService.GetTrackByUserAsync(new GrpcShared.DTO.Db.DbRequestMessage | |||
| // { | |||
| // Id = "63074188426efd486fadd74d" | |||
| // }); | |||
| var trackByUser = await identityService.GetTrackByUserAsync(new GrpcShared.DTO.Db.DbRequestMessage | |||
| { | |||
| Id = userId | |||
| }); | |||
| //await identityService.DeleteTrackAsync(new GrpcShared.DTO.Db.DbRequestMessage | |||
| // { | |||
| // Id = "630743c91631901f903f9254" | |||
| // }); | |||
| // await identityService.SaveTrackAsync(new GrpcShared.DTO.Db.SaveTrackRequest | |||
| // { | |||
| // TrackId = track.Item.Id, | |||
| // Title = track.Item.Name, | |||
| // Album = track.Item.Album.Name, | |||
| // Artist = track.Item.Artists[0].Name, | |||
| // UserId = "63074188426efd486fadd74d" | |||
| // Id = | |||
| // }); | |||
| //find id from local storage | |||
| await identityService.DeleteUserAsync(new GrpcShared.DTO.Db.DbRequestMessage | |||
| await identityService.SaveTrackAsync(new GrpcShared.DTO.Db.SaveTrackRequest | |||
| { | |||
| Id = "630748c8d149033aaf5a774a" | |||
| TrackId = track.Item.Id, | |||
| Title = track.Item.Name, | |||
| Album = track.Item.Album.Name, | |||
| Artist = track.Item.Artists[0].Name, | |||
| UserId = userId | |||
| }); | |||
| //find id from local storage | |||
| //await identityService.DeleteUserAsync(new GrpcShared.DTO.Db.DbRequestMessage | |||
| // { | |||
| // Id = userId | |||
| // }); | |||
| } | |||
| } | |||
| @@ -9,6 +9,7 @@ | |||
| @inject IAuthClientService AuthService | |||
| @inject ITrackClientService SearchService | |||
| @using System.Security.Claims | |||
| @inject Blazored.LocalStorage.ILocalStorageService localStorage | |||
| @@ -35,7 +36,12 @@ Dobrodošli u našu NemAn aplikaciju. | |||
| @code { | |||
| private string? message; | |||
| protected override async Task OnInitializedAsync() | |||
| { | |||
| var userId = await localStorage.GetItemAsync<string>("user_info"); | |||
| if (userId != null) NavigationManager.NavigateTo("/home"); | |||
| } | |||
| private async Task LoginUser() | |||
| { | |||
| //var response = await SearchService.GetListSearchAsync(new GrpcShared.DTO.Search.SearchRequest() { Query="venom", Type = "track"}); | |||
| @@ -48,5 +48,10 @@ namespace NemAnBlazor.Services | |||
| { | |||
| return await _serviceClient.SaveUserAsync(user); | |||
| } | |||
| public async Task<VoidMessage> UpdateTokenAsync(UserResponse user) | |||
| { | |||
| return await _serviceClient.UpdateTokenAsync(user); | |||
| } | |||
| } | |||
| } | |||
| @@ -12,5 +12,6 @@ namespace NemAnBlazor.Services.Interfaces | |||
| Task<VoidMessage> DeleteTrackAsync(DbRequestMessage id); | |||
| Task<VoidMessage> SaveUserAsync(UserResponse user); | |||
| Task<VoidMessage> DeleteUserAsync(DbRequestMessage user); | |||
| Task<VoidMessage> UpdateTokenAsync(UserResponse user); | |||
| } | |||
| } | |||
| @@ -1,18 +1,28 @@ | |||
| using Blazored.LocalStorage; | |||
| using GrpcShared.DTO; | |||
| using GrpcShared.DTO.Db; | |||
| using NemAnBlazor.Services.Interfaces; | |||
| namespace NemAnBlazor | |||
| { | |||
| public static class SpotifyHelper | |||
| { | |||
| public static async Task<string?> TryRefreshToken(IAuthClientService authService, TokenMessage msg, ILocalStorageService localStorage) | |||
| public static async Task<string?> TryRefreshToken | |||
| (IAuthClientService authService, | |||
| TokenMessage msg,UserResponse user, | |||
| ILocalStorageService localStorage, | |||
| IIdentityClientService identityService) | |||
| { | |||
| var refreshResponse = await authService.RefreshAccessToken(msg); | |||
| if (refreshResponse.AccessToken != null) | |||
| { | |||
| await localStorage.SetItemAsync<string>("token", refreshResponse.AccessToken); | |||
| await identityService.UpdateTokenAsync(new UserResponse | |||
| { | |||
| Id = user.Id, | |||
| Token = refreshResponse.AccessToken, | |||
| RefreshToken = user.RefreshToken | |||
| }); | |||
| return refreshResponse.AccessToken; | |||
| } | |||
| else return null; | |||
| @@ -11,4 +11,9 @@ | |||
| <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" /> | |||
| <PackageReference Include="protobuf-net.Grpc" Version="1.0.171" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <ProjectReference Include="..\gRPCServer\SpotifyService.csproj" /> | |||
| <ProjectReference Include="..\IdentityProvider\IdentityProvider.csproj" /> | |||
| </ItemGroup> | |||
| </Project> | |||
| @@ -3,18 +3,23 @@ namespace SpotifyWorker | |||
| public class Worker : BackgroundService | |||
| { | |||
| private readonly ILogger<Worker> _logger; | |||
| private HttpClient _httpClient; | |||
| public Worker(ILogger<Worker> logger) | |||
| { | |||
| _logger = logger; | |||
| } | |||
| public override Task StartAsync(CancellationToken cancellationToken) | |||
| { | |||
| _httpClient = new HttpClient(); | |||
| return base.StartAsync(cancellationToken); | |||
| } | |||
| protected override async Task ExecuteAsync(CancellationToken stoppingToken) | |||
| { | |||
| while (!stoppingToken.IsCancellationRequested) | |||
| { | |||
| _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); | |||
| await Task.Delay(1000, stoppingToken); | |||
| await Task.Delay(5000, stoppingToken); | |||
| } | |||
| } | |||
| } | |||