| 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; } | |||||
| } | |||||
| } |
| 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<ClientSecrets> GetClientSecrets(); | |||||
| Task<UserInfoResponse> GetUserInfo(TokenMessage token); | |||||
| } | } | ||||
| } | } |
| //using IdentityProvider.Protos.AuthService; | //using IdentityProvider.Protos.AuthService; | ||||
| 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; | ||||
| //AUTHORIZATION HEADER | //AUTHORIZATION HEADER | ||||
| http.DefaultRequestHeaders.Add(HeaderNames.Authorization, "Basic " + Convert.ToBase64String(contentType)); | http.DefaultRequestHeaders.Add(HeaderNames.Authorization, "Basic " + Convert.ToBase64String(contentType)); | ||||
| //ACCEPT HEADER | |||||
| http.DefaultRequestHeaders.Accept.Add( | |||||
| new MediaTypeWithQualityHeaderValue("application/json")); | |||||
| ////ACCEPT HEADER | |||||
| //http.DefaultRequestHeaders.Accept.Add( | |||||
| // new MediaTypeWithQualityHeaderValue("application/json")); | |||||
| //BODY PARAMS | //BODY PARAMS | ||||
| var requestBody = new Dictionary<string, string>(); | var requestBody = new Dictionary<string, string>(); | ||||
| var response = await http.PostAsync(url, new FormUrlEncodedContent(requestBody)); | var response = await http.PostAsync(url, new FormUrlEncodedContent(requestBody)); | ||||
| var contents = JsonConvert.DeserializeObject<TokenResponse>(await response.Content.ReadAsStringAsync()); | 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 | |||||
| }; | |||||
| if (contents != null) | |||||
| return new TokenResponse | |||||
| { | |||||
| access_token = contents!.access_token, | |||||
| refresh_token = contents!.refresh_token, | |||||
| expires_in = contents!.expires_in | |||||
| }; | |||||
| else return null; | |||||
| } | } | ||||
| public async Task<CodeRequest> GetAuthParams() | public async Task<CodeRequest> GetAuthParams() | ||||
| return await Task.FromResult(authParams); | return await Task.FromResult(authParams); | ||||
| } | } | ||||
| public async Task<UserInfoResponse> GetUserInfo(TokenMessage token) | |||||
| { | |||||
| var http = _httpClientFactory.CreateClient(); | |||||
| http.BaseAddress = new Uri(SpotifyService.GLOBALS.SPOTIFYURL); | |||||
| //AUTHORIZATION HEADER | |||||
| 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" | ||||
| } | } | ||||
| } | } |
| <CascadingAuthenticationState> | |||||
| @using NemAnBlazor.Pages | |||||
| <CascadingAuthenticationState> | |||||
| <Router AppAssembly="@typeof(App).Assembly"> | <Router AppAssembly="@typeof(App).Assembly"> | ||||
| <Found Context="routeData"> | <Found Context="routeData"> | ||||
| <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" > | <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" > | ||||
| <NotAuthorized>Sorry nisi autorizovan</NotAuthorized> | |||||
| <NotAuthorized><LoginRedirect/></NotAuthorized> | |||||
| </AuthorizeRouteView> | </AuthorizeRouteView> | ||||
| <FocusOnNavigate RouteData="@routeData" Selector="h1" /> | <FocusOnNavigate RouteData="@routeData" Selector="h1" /> | ||||
| </Found> | </Found> |
| using Blazored.SessionStorage; | |||||
| using System.Security.Claims; | |||||
| namespace NemAnBlazor | |||||
| { | |||||
| public class AuthProvider : AuthenticationStateProvider | |||||
| { | |||||
| private readonly ISessionStorageService _sessionStorage; | |||||
| public AuthProvider(ISessionStorageService sessionStorage) | |||||
| { | |||||
| _sessionStorage = sessionStorage; | |||||
| } | |||||
| public override async Task<AuthenticationState> GetAuthenticationStateAsync() | |||||
| { | |||||
| string token = await _sessionStorage.GetItemAsync<string>("token"); | |||||
| ClaimsIdentity identity = new (); | |||||
| ClaimsPrincipal user = new (identity); | |||||
| AuthenticationState state = new(user); | |||||
| NotifyAuthenticationStateChanged(Task.FromResult(state)); | |||||
| return state; | |||||
| } | |||||
| } | |||||
| } |
| <ImplicitUsings>enable</ImplicitUsings> | <ImplicitUsings>enable</ImplicitUsings> | ||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | |||||
| <Optimize>True</Optimize> | |||||
| </PropertyGroup> | |||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | |||||
| <Optimize>False</Optimize> | |||||
| </PropertyGroup> | |||||
| <ItemGroup> | <ItemGroup> | ||||
| <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" /> |
| @code { | @code { | ||||
| protected override async Task OnInitializedAsync() | protected override async Task OnInitializedAsync() | ||||
| { | { | ||||
| string url = NavigationMgr.Uri; | string url = NavigationMgr.Uri; | ||||
| var response = await AuthService.GetAccessToken(new GrpcShared.DTO.Auth.TokenRequest { code = code}); | var response = await AuthService.GetAccessToken(new GrpcShared.DTO.Auth.TokenRequest { code = code}); | ||||
| //if (response.access_token == null) NavigationMgr.NavigateTo("/"); | |||||
| //store access token in local storage | //store access token in local storage | ||||
| await sessionStorage.SetItemAsync("token", response.access_token); | await sessionStorage.SetItemAsync("token", response.access_token); | ||||
| await sessionStorage.SetItemAsync("refresh_token", response.refresh_token); | await sessionStorage.SetItemAsync("refresh_token", response.refresh_token); | ||||
| //redirect to home | //redirect to home | ||||
| NavigationMgr.NavigateTo("/home"); | NavigationMgr.NavigateTo("/home"); | ||||
| } | } |
| @page "/home" | @page "/home" | ||||
| @attribute [Authorize] | |||||
| <h3>Home</h3> | <h3>Home</h3> | ||||
| <p>login radi</p> | <p>login radi</p> | ||||
| <p>autorizovan si</p> | <p>autorizovan si</p> | ||||
| </Authorized> | </Authorized> | ||||
| <NotAuthorized> | <NotAuthorized> | ||||
| <p>nisi autorizovan</p> | |||||
| <LoginRedirect/> | |||||
| </NotAuthorized> | </NotAuthorized> | ||||
| </AuthorizeView> | </AuthorizeView> | ||||
| @code { | @code { |
| @using NemAnBlazor.Services.Interfaces | @using NemAnBlazor.Services.Interfaces | ||||
| @inject NavigationManager NavigationManager | @inject NavigationManager NavigationManager | ||||
| @inject IAuthClientService AuthService | @inject IAuthClientService AuthService | ||||
| @inject ITrackClientService SearchService | |||||
| <PageTitle>Index</PageTitle> | <PageTitle>Index</PageTitle> | ||||
| <h1>Pozdrav Diligent!</h1> | <h1>Pozdrav Diligent!</h1> |
| @inject NavigationManager UriHelper | |||||
| @code { | |||||
| protected override void OnInitialized() | |||||
| { | |||||
| UriHelper.NavigateTo("/"); | |||||
| } | |||||
| } |
| builder.Services.AddScoped<ITrackClientService, TrackClientService>(); | builder.Services.AddScoped<ITrackClientService, TrackClientService>(); | ||||
| builder.Services.AddScoped<IAuthClientService, AuthClientService>(); | builder.Services.AddScoped<IAuthClientService, AuthClientService>(); | ||||
| builder.Services.AddBlazoredSessionStorage(); | builder.Services.AddBlazoredSessionStorage(); | ||||
| builder.Services.AddScoped<AuthenticationStateProvider, AuthProvider>(); | |||||
| builder.Services.AddScoped<AuthenticationStateProvider, AuthClientService>(); | |||||
| builder.Services.AddAuthorizationCore(); | builder.Services.AddAuthorizationCore(); | ||||
| await builder.Build().RunAsync(); | await builder.Build().RunAsync(); | ||||
| 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 Blazored.SessionStorage; | |||||
| namespace NemAnBlazor.Services | namespace NemAnBlazor.Services | ||||
| { | { | ||||
| public class AuthClientService : IAuthClientService | |||||
| public class AuthClientService : AuthenticationStateProvider, IAuthClientService | |||||
| { | { | ||||
| private IAuthService _serviceClient; | private IAuthService _serviceClient; | ||||
| public AuthClientService(GrpcChannel grpcChannel) | |||||
| private readonly ISessionStorageService _sessionStorage; | |||||
| public AuthClientService(GrpcChannel grpcChannel, ISessionStorageService sessionStorage) | |||||
| { | { | ||||
| _serviceClient = grpcChannel.CreateGrpcService<IAuthService>(); | _serviceClient = grpcChannel.CreateGrpcService<IAuthService>(); | ||||
| _sessionStorage = sessionStorage; | |||||
| } | } | ||||
| public async Task<TokenResponse> GetAccessToken(TokenRequest request) | public async Task<TokenResponse> GetAccessToken(TokenRequest request) | ||||
| { | { | ||||
| return await _serviceClient.GetAccessToken(request); | return await _serviceClient.GetAccessToken(request); | ||||
| } | } | ||||
| 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; | |||||
| } | |||||
| public async Task<CodeRequest> GetAuthParams() | public async Task<CodeRequest> GetAuthParams() | ||||
| { | { | ||||
| return await _serviceClient.GetAuthParams(); | return await _serviceClient.GetAuthParams(); | ||||
| } | } | ||||
| public async Task<UserInfoResponse> GetUserInfo(TokenMessage token) | |||||
| { | |||||
| return await _serviceClient.GetUserInfo(token); | |||||
| } | |||||
| } | } | ||||
| } | } |
| 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 NemAnBlazor | @using NemAnBlazor | ||||
| @using NemAnBlazor.Shared | @using NemAnBlazor.Shared | ||||
| @using System.Web | @using System.Web | ||||
| @using Microsoft.AspNetCore.Components.Authorization | |||||
| @using Microsoft.AspNetCore.Components.Authorization | |||||
| @using Microsoft.AspNetCore.Authorization |