feat: add authentication using Google OAuth token
https://levelup.gitconnected.com/how-to-sign-in-with-google-in-angular-and-use-jwt-based-net-core-api-authentication-rsa-6635719fb86c
This commit is contained in:
parent
59c3a9f704
commit
ceaba3eb2d
@ -3,7 +3,7 @@ namespace Server.Configurations;
|
|||||||
public class SmtpCredentials
|
public class SmtpCredentials
|
||||||
{
|
{
|
||||||
public string Host { get; set; } = null!;
|
public string Host { get; set; } = null!;
|
||||||
public int Port { get; set; }
|
public string Port { get; set; }
|
||||||
public string User { get; set; } = null!;
|
public string User { get; set; } = null!;
|
||||||
public string Password { get; set; } = null!;
|
public string Password { get; set; } = null!;
|
||||||
}
|
}
|
@ -49,7 +49,7 @@ public class AuthenticationController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("authenticate")]
|
[HttpPost("authenticate")]
|
||||||
public async Task<IActionResult> GetTokenAsync(AuthenticationRequest authRequest)
|
public async Task<IActionResult> Authenticate(AuthenticationRequest authRequest)
|
||||||
{
|
{
|
||||||
var (succeeded, authResponse, refreshToken) =
|
var (succeeded, authResponse, refreshToken) =
|
||||||
await _authService.AuthenticateAsync(authRequest);
|
await _authService.AuthenticateAsync(authRequest);
|
||||||
@ -64,6 +64,22 @@ public class AuthenticationController : ControllerBase
|
|||||||
return Ok(authResponse);
|
return Ok(authResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("googleoauth")]
|
||||||
|
public async Task<IActionResult> AuthenticateWithGoogle(GoogleAuthenticationRequest authRequest)
|
||||||
|
{
|
||||||
|
var (succeeded, authResponse, refreshToken) =
|
||||||
|
await _authService.AuthenticateWithGoogleAsync(authRequest);
|
||||||
|
|
||||||
|
if (!succeeded)
|
||||||
|
{
|
||||||
|
return BadRequest(authResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetRefreshTokenInCookie(refreshToken!);
|
||||||
|
|
||||||
|
return Ok(authResponse);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("renew-session")]
|
[HttpPost("renew-session")]
|
||||||
public async Task<IActionResult> RenewTokens()
|
public async Task<IActionResult> RenewTokens()
|
||||||
{
|
{
|
||||||
|
@ -16,20 +16,22 @@ using Server.Services;
|
|||||||
using SharedModels.DataTransferObjects;
|
using SharedModels.DataTransferObjects;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
var services = builder.Services;
|
||||||
|
var configuration = builder.Configuration;
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
|
|
||||||
builder.Services.AddControllers().AddNewtonsoftJson(options => {
|
services.AddControllers().AddNewtonsoftJson(options => {
|
||||||
options.SerializerSettings.Formatting = Formatting.Indented;
|
options.SerializerSettings.Formatting = Formatting.Indented;
|
||||||
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
||||||
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Error;
|
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Error;
|
||||||
options.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
|
options.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
|
||||||
});
|
});
|
||||||
builder.Services.AddHttpContextAccessor();
|
services.AddHttpContextAccessor();
|
||||||
|
|
||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen(options => {
|
services.AddSwaggerGen(options => {
|
||||||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {
|
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {
|
||||||
Scheme = "Bearer",
|
Scheme = "Bearer",
|
||||||
BearerFormat = "JWT",
|
BearerFormat = "JWT",
|
||||||
@ -53,22 +55,25 @@ builder.Services.AddSwaggerGen(options => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddCors(options => {
|
services.AddCors(options => {
|
||||||
options.AddDefaultPolicy(policy => policy.AllowAnyOrigin()
|
options.AddDefaultPolicy(policy => policy.AllowAnyOrigin()
|
||||||
.AllowAnyHeader().AllowAnyMethod());
|
.AllowAnyHeader().AllowAnyMethod());
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddIdentityCore<User>(options =>
|
services.AddIdentityCore<User>(options =>
|
||||||
{
|
{
|
||||||
options.User.RequireUniqueEmail = true;
|
options.User.RequireUniqueEmail = true;
|
||||||
options.Password.RequiredLength = 8;
|
options.Password.RequiredLength = 8;
|
||||||
}).AddRoles<IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();
|
}).AddRoles<IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();
|
||||||
|
|
||||||
// Configuration from AppSettings
|
// Configuration from AppSettings
|
||||||
builder.Services.Configure<Jwt>(builder.Configuration.GetSection("Jwt"));
|
services.Configure<SmtpCredentials>(configuration.GetSection("SmtpCredentials"));
|
||||||
|
services.Configure<Jwt>(configuration.GetSection("Jwt"));
|
||||||
|
|
||||||
// Adding Authentication - JWT
|
// Adding Authentication - JWT
|
||||||
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
.AddJwtBearer(options => {
|
.AddJwtBearer(options =>
|
||||||
|
{
|
||||||
// options.RequireHttpsMetadata = false;
|
// options.RequireHttpsMetadata = false;
|
||||||
// options.SaveToken = false;
|
// options.SaveToken = false;
|
||||||
options.TokenValidationParameters = new TokenValidationParameters
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
@ -77,15 +82,14 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|||||||
ValidateAudience = false,
|
ValidateAudience = false,
|
||||||
ValidateIssuer = false,
|
ValidateIssuer = false,
|
||||||
ValidateLifetime = true,
|
ValidateLifetime = true,
|
||||||
ValidIssuer = builder.Configuration["Jwt:Issuer"],
|
ValidIssuer = configuration["Jwt:Issuer"],
|
||||||
ValidAudience = builder.Configuration["Jwt:Audience"],
|
ValidAudience = configuration["Jwt:Audience"],
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(
|
IssuerSigningKey = new SymmetricSecurityKey(
|
||||||
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
|
Encoding.UTF8.GetBytes(configuration["Jwt:Key"]))
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
builder.Services.Configure<SmtpCredentials>(builder.Configuration.GetSection("SmtpCredentials"));
|
|
||||||
|
|
||||||
builder.Services.AddAuthorization(options => {
|
services.AddAuthorization(options => {
|
||||||
// options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
|
// options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
|
||||||
|
|
||||||
// Policies for accessing endpoints on a top level based on user role
|
// Policies for accessing endpoints on a top level based on user role
|
||||||
@ -100,62 +104,62 @@ builder.Services.AddAuthorization(options => {
|
|||||||
policy.RequireRole(Identity.Roles.Administrator.ToString()));
|
policy.RequireRole(Identity.Roles.Administrator.ToString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddAutoMapper(typeof(MapperInitializer));
|
services.AddAutoMapper(typeof(MapperInitializer));
|
||||||
|
|
||||||
builder.Services.AddScoped<IEmailSenderService, EmailSenderService>();
|
services.AddScoped<IEmailSenderService, EmailSenderService>();
|
||||||
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
|
services.AddScoped<IAuthenticationService, AuthenticationService>();
|
||||||
|
|
||||||
builder.Services.AddScoped<ICountryManagementService, CountryManagementService>();
|
services.AddScoped<ICountryManagementService, CountryManagementService>();
|
||||||
builder.Services.AddScoped<IStateManagementService, StateManagementService>();
|
services.AddScoped<IStateManagementService, StateManagementService>();
|
||||||
builder.Services.AddScoped<ICityManagementService, CityManagementService>();
|
services.AddScoped<ICityManagementService, CityManagementService>();
|
||||||
builder.Services.AddScoped<IAddressManagementService, AddressManagementService>();
|
services.AddScoped<IAddressManagementService, AddressManagementService>();
|
||||||
builder.Services.AddScoped<ITicketManagementService, TicketManagementService>();
|
services.AddScoped<ITicketManagementService, TicketManagementService>();
|
||||||
builder.Services.AddScoped<ITicketGroupManagementService, TicketGroupManagementService>();
|
services.AddScoped<ITicketGroupManagementService, TicketGroupManagementService>();
|
||||||
builder.Services.AddScoped<IReviewManagementService, ReviewManagementService>();
|
services.AddScoped<IReviewManagementService, ReviewManagementService>();
|
||||||
builder.Services.AddScoped<ICompanyManagementService, CompanyManagementService>();
|
services.AddScoped<ICompanyManagementService, CompanyManagementService>();
|
||||||
builder.Services.AddScoped<IVehicleManagementService, VehicleManagementService>();
|
services.AddScoped<IVehicleManagementService, VehicleManagementService>();
|
||||||
builder.Services.AddScoped<IVehicleEnrollmentManagementService, VehicleEnrollmentManagementService>();
|
services.AddScoped<IVehicleEnrollmentManagementService, VehicleEnrollmentManagementService>();
|
||||||
builder.Services.AddScoped<IRouteManagementService, RouteManagementService>();
|
services.AddScoped<IRouteManagementService, RouteManagementService>();
|
||||||
builder.Services.AddScoped<IRouteAddressManagementService, RouteAddressManagementService>();
|
services.AddScoped<IRouteAddressManagementService, RouteAddressManagementService>();
|
||||||
|
|
||||||
builder.Services.AddScoped<ISortHelper<ExpandoObject>, SortHelper<ExpandoObject>>();
|
services.AddScoped<ISortHelper<ExpandoObject>, SortHelper<ExpandoObject>>();
|
||||||
|
|
||||||
builder.Services.AddScoped<IDataShaper<CountryDto>, DataShaper<CountryDto>>();
|
services.AddScoped<IDataShaper<CountryDto>, DataShaper<CountryDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<StateDto>, DataShaper<StateDto>>();
|
services.AddScoped<IDataShaper<StateDto>, DataShaper<StateDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<CityDto>, DataShaper<CityDto>>();
|
services.AddScoped<IDataShaper<CityDto>, DataShaper<CityDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<AddressDto>, DataShaper<AddressDto>>();
|
services.AddScoped<IDataShaper<AddressDto>, DataShaper<AddressDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<TicketDto>, DataShaper<TicketDto>>();
|
services.AddScoped<IDataShaper<TicketDto>, DataShaper<TicketDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<TicketGroupDto>, DataShaper<TicketGroupDto>>();
|
services.AddScoped<IDataShaper<TicketGroupDto>, DataShaper<TicketGroupDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<TicketGroupWithTicketsDto>, DataShaper<TicketGroupWithTicketsDto>>();
|
services.AddScoped<IDataShaper<TicketGroupWithTicketsDto>, DataShaper<TicketGroupWithTicketsDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<ReviewDto>, DataShaper<ReviewDto>>();
|
services.AddScoped<IDataShaper<ReviewDto>, DataShaper<ReviewDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<CompanyDto>, DataShaper<CompanyDto>>();
|
services.AddScoped<IDataShaper<CompanyDto>, DataShaper<CompanyDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<VehicleDto>, DataShaper<VehicleDto>>();
|
services.AddScoped<IDataShaper<VehicleDto>, DataShaper<VehicleDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<VehicleEnrollmentDto>, DataShaper<VehicleEnrollmentDto>>();
|
services.AddScoped<IDataShaper<VehicleEnrollmentDto>, DataShaper<VehicleEnrollmentDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<VehicleEnrollmentWithDetailsDto>, DataShaper<VehicleEnrollmentWithDetailsDto>>();
|
services.AddScoped<IDataShaper<VehicleEnrollmentWithDetailsDto>, DataShaper<VehicleEnrollmentWithDetailsDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<RouteDto>, DataShaper<RouteDto>>();
|
services.AddScoped<IDataShaper<RouteDto>, DataShaper<RouteDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<RouteWithAddressesDto>, DataShaper<RouteWithAddressesDto>>();
|
services.AddScoped<IDataShaper<RouteWithAddressesDto>, DataShaper<RouteWithAddressesDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<RouteAddressDto>, DataShaper<RouteAddressDto>>();
|
services.AddScoped<IDataShaper<RouteAddressDto>, DataShaper<RouteAddressDto>>();
|
||||||
|
|
||||||
builder.Services.AddScoped<IPager<ExpandoObject>, Pager<ExpandoObject>>();
|
services.AddScoped<IPager<ExpandoObject>, Pager<ExpandoObject>>();
|
||||||
|
|
||||||
builder.Services.AddScoped<AutomationService>();
|
services.AddScoped<AutomationService>();
|
||||||
builder.Services.AddScoped<IReportService, ReportService>();
|
services.AddScoped<IReportService, ReportService>();
|
||||||
|
|
||||||
builder.Services.AddScoped<IStatisticsService, StatisticsService>();
|
services.AddScoped<IStatisticsService, StatisticsService>();
|
||||||
builder.Services.AddScoped<IDataShaper<UserDto>, DataShaper<UserDto>>();
|
services.AddScoped<IDataShaper<UserDto>, DataShaper<UserDto>>();
|
||||||
builder.Services.AddScoped<IDataShaper<ExpandoObject>, DataShaper<ExpandoObject>>();
|
services.AddScoped<IDataShaper<ExpandoObject>, DataShaper<ExpandoObject>>();
|
||||||
|
|
||||||
// Adding DB Context with PostgreSQL
|
// Adding DB Context with PostgreSQL
|
||||||
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
|
var connectionString = configuration.GetConnectionString("DefaultConnection");
|
||||||
builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
services.AddDbContext<ApplicationDbContext>(options =>
|
||||||
options.UseNpgsql(connectionString));
|
options.UseNpgsql(connectionString));
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Data seeding
|
// Data seeding
|
||||||
using var scope = app.Services.CreateScope();
|
using var scope = app.Services.CreateScope();
|
||||||
var services = scope.ServiceProvider;
|
var serviceProvider = scope.ServiceProvider;
|
||||||
await SeedData.Initialize(services);
|
await SeedData.Initialize(serviceProvider);
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
|
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
|
||||||
|
<PackageReference Include="Google.Apis.Auth" Version="1.60.0" />
|
||||||
<PackageReference Include="MailKit" Version="4.0.0" />
|
<PackageReference Include="MailKit" Version="4.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="6.0.9" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.14" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.14" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.9" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.9" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.9" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.9" />
|
||||||
|
@ -3,6 +3,7 @@ using System.IdentityModel.Tokens.Jwt;
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Google.Apis.Auth;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
@ -17,24 +18,28 @@ namespace Server.Services;
|
|||||||
|
|
||||||
public class AuthenticationService : IAuthenticationService
|
public class AuthenticationService : IAuthenticationService
|
||||||
{
|
{
|
||||||
|
private readonly Jwt _jwt;
|
||||||
|
|
||||||
private readonly UserManager<User> _userManager;
|
private readonly UserManager<User> _userManager;
|
||||||
private readonly RoleManager<IdentityRole> _roleManager;
|
private readonly RoleManager<IdentityRole> _roleManager;
|
||||||
private readonly Jwt _jwt;
|
|
||||||
private readonly IHttpContextAccessor _contextAccessor;
|
private readonly IHttpContextAccessor _contextAccessor;
|
||||||
private readonly LinkGenerator _linkGenerator;
|
private readonly LinkGenerator _linkGenerator;
|
||||||
private readonly IEmailSenderService _emailSender;
|
private readonly IEmailSenderService _emailSender;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
public AuthenticationService(UserManager<User> userManager,
|
public AuthenticationService(UserManager<User> userManager,
|
||||||
RoleManager<IdentityRole> roleManager, IOptions<Jwt> jwt,
|
RoleManager<IdentityRole> roleManager, IOptions<Jwt> jwt,
|
||||||
IHttpContextAccessor contextAccessor, LinkGenerator linkGenerator,
|
IHttpContextAccessor contextAccessor, LinkGenerator linkGenerator,
|
||||||
IEmailSenderService emailSender)
|
IEmailSenderService emailSender, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
|
_jwt = jwt.Value;
|
||||||
|
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_roleManager = roleManager;
|
_roleManager = roleManager;
|
||||||
_jwt = jwt.Value;
|
|
||||||
_contextAccessor = contextAccessor;
|
_contextAccessor = contextAccessor;
|
||||||
_linkGenerator = linkGenerator;
|
_linkGenerator = linkGenerator;
|
||||||
_emailSender = emailSender;
|
_emailSender = emailSender;
|
||||||
|
_configuration = configuration;
|
||||||
|
|
||||||
_userManager.UserValidators.Clear();
|
_userManager.UserValidators.Clear();
|
||||||
}
|
}
|
||||||
@ -70,15 +75,23 @@ public class AuthenticationService : IAuthenticationService
|
|||||||
return (false, $"{createUserResult.Errors?.First().Description}");
|
return (false, $"{createUserResult.Errors?.First().Description}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await _userManager.AddToRoleAsync(user, Constants.Identity.DefaultRole.ToString());
|
||||||
|
|
||||||
var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||||
var confirmationLink = _linkGenerator.GetUriByAction(_contextAccessor.HttpContext,
|
var confirmationLink = _linkGenerator.GetUriByAction(_contextAccessor.HttpContext,
|
||||||
"confirmEmail", "authentication",
|
"confirmEmail", "authentication",
|
||||||
new { email = user.Email, token = token, redirectionUrl = regRequest.EmailConfirmationRedirectUrl },
|
new { email = user.Email, token = token, redirectionUrl = regRequest.EmailConfirmationRedirectUrl },
|
||||||
_contextAccessor.HttpContext.Request.Scheme);
|
_contextAccessor.HttpContext.Request.Scheme);
|
||||||
|
|
||||||
await _emailSender.SendMail(user.Email, "Email confirmation", confirmationLink);
|
try
|
||||||
|
{
|
||||||
|
await _emailSender.SendMail(user.Email, "Email confirmation", confirmationLink);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
await _userManager.AddToRoleAsync(user, Constants.Identity.DefaultRole.ToString());
|
|
||||||
return (true, $"User registered with email {user.Email}. Before signing in confirm your email" +
|
return (true, $"User registered with email {user.Email}. Before signing in confirm your email" +
|
||||||
$"by following a link sent to registered email address.");
|
$"by following a link sent to registered email address.");
|
||||||
}
|
}
|
||||||
@ -100,8 +113,8 @@ public class AuthenticationService : IAuthenticationService
|
|||||||
return (true, $"Email {email} confirmed");
|
return (true, $"Email {email} confirmed");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(bool succeeded, AuthenticationResponse authResponse,
|
public async Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
|
||||||
string? refreshToken)> AuthenticateAsync(AuthenticationRequest authRequest)
|
AuthenticateAsync(AuthenticationRequest authRequest)
|
||||||
{
|
{
|
||||||
var authResponse = new AuthenticationResponse();
|
var authResponse = new AuthenticationResponse();
|
||||||
|
|
||||||
@ -145,6 +158,56 @@ public class AuthenticationService : IAuthenticationService
|
|||||||
return (true, authResponse, refreshTokenString);
|
return (true, authResponse, refreshTokenString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
|
||||||
|
AuthenticateWithGoogleAsync(GoogleAuthenticationRequest authRequest)
|
||||||
|
{
|
||||||
|
GoogleJsonWebSignature.ValidationSettings settings = new GoogleJsonWebSignature.ValidationSettings();
|
||||||
|
|
||||||
|
settings.Audience = new List<string> { _configuration["Authentication:Google:ClientId"] };
|
||||||
|
|
||||||
|
GoogleJsonWebSignature.Payload payload = GoogleJsonWebSignature.ValidateAsync(authRequest.IdToken, settings).Result;
|
||||||
|
|
||||||
|
var authResponse = new AuthenticationResponse();
|
||||||
|
|
||||||
|
var user = await _userManager.FindByEmailAsync(payload.Email);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
var createUserResult = await _userManager.CreateAsync(new User
|
||||||
|
{
|
||||||
|
Email = payload.Email,
|
||||||
|
EmailConfirmed = payload.EmailVerified,
|
||||||
|
FirstName = payload.GivenName,
|
||||||
|
LastName = payload.FamilyName
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!createUserResult.Succeeded)
|
||||||
|
{
|
||||||
|
authResponse.Message = $"{createUserResult.Errors?.First().Description}";
|
||||||
|
return (false, authResponse, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string refreshTokenString;
|
||||||
|
|
||||||
|
if (user.RefreshTokens.Any(t => t.IsActive))
|
||||||
|
{
|
||||||
|
var activeRefreshToken =
|
||||||
|
user.RefreshTokens.First(t => t.IsActive);
|
||||||
|
refreshTokenString = activeRefreshToken.Token;
|
||||||
|
authResponse.RefreshTokenExpirationDate = activeRefreshToken.ExpiryDateTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var refreshToken = CreateRefreshToken();
|
||||||
|
refreshTokenString = refreshToken.Token;
|
||||||
|
authResponse.RefreshTokenExpirationDate = refreshToken.ExpiryDateTime;
|
||||||
|
user.RefreshTokens.Add(refreshToken);
|
||||||
|
await _userManager.UpdateAsync(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true, authResponse, refreshTokenString);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<(bool succeeded, AuthenticationResponse authResponse,
|
public async Task<(bool succeeded, AuthenticationResponse authResponse,
|
||||||
string? refreshToken)> RenewRefreshTokenAsync(string? token)
|
string? refreshToken)> RenewRefreshTokenAsync(string? token)
|
||||||
{
|
{
|
||||||
@ -222,7 +285,7 @@ public class AuthenticationService : IAuthenticationService
|
|||||||
var claims = new[]
|
var claims = new[]
|
||||||
{
|
{
|
||||||
new Claim(JwtStandardClaimNames.Sub, user.Id),
|
new Claim(JwtStandardClaimNames.Sub, user.Id),
|
||||||
new Claim(JwtStandardClaimNames.Name, user.LastName + user.FirstName + user.Patronymic),
|
new Claim(JwtStandardClaimNames.Name, $"{user.LastName} {user.FirstName} {user.Patronymic}"),
|
||||||
new Claim(JwtStandardClaimNames.GivenName, user.FirstName),
|
new Claim(JwtStandardClaimNames.GivenName, user.FirstName),
|
||||||
new Claim(JwtStandardClaimNames.FamilyName, user.LastName),
|
new Claim(JwtStandardClaimNames.FamilyName, user.LastName),
|
||||||
new Claim(JwtStandardClaimNames.MiddleName, user.Patronymic),
|
new Claim(JwtStandardClaimNames.MiddleName, user.Patronymic),
|
||||||
|
@ -34,18 +34,11 @@ public class EmailSenderService : IEmailSenderService
|
|||||||
mailMessage.Subject = $"{applicationName}. {subject}";
|
mailMessage.Subject = $"{applicationName}. {subject}";
|
||||||
mailMessage.Body = new TextPart(MimeKit.Text.TextFormat.Text) { Text = message};
|
mailMessage.Body = new TextPart(MimeKit.Text.TextFormat.Text) { Text = message};
|
||||||
|
|
||||||
try
|
await _smtpClient.ConnectAsync(_smtpCredentials.Host, Int32.Parse(_smtpCredentials.Port), false);
|
||||||
{
|
await _smtpClient.AuthenticateAsync(Encoding.ASCII, _smtpCredentials.User, _smtpCredentials.Password);
|
||||||
await _smtpClient.ConnectAsync(_smtpCredentials.Host, _smtpCredentials.Port, true);
|
await _smtpClient.SendAsync(mailMessage);
|
||||||
await _smtpClient.AuthenticateAsync(Encoding.ASCII, _smtpCredentials.User, _smtpCredentials.Password);
|
await _smtpClient.DisconnectAsync(true);
|
||||||
await _smtpClient.SendAsync(mailMessage);
|
|
||||||
await _smtpClient.DisconnectAsync(true);
|
return (true, "Letter has been sent successfully");
|
||||||
return (true, "Letter has been sent successfully");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine(e);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,6 +11,9 @@ public interface IAuthenticationService
|
|||||||
|
|
||||||
Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
|
Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
|
||||||
AuthenticateAsync(AuthenticationRequest authRequest);
|
AuthenticateAsync(AuthenticationRequest authRequest);
|
||||||
|
|
||||||
|
Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
|
||||||
|
AuthenticateWithGoogleAsync(GoogleAuthenticationRequest authRequest);
|
||||||
|
|
||||||
Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
|
Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
|
||||||
RenewRefreshTokenAsync(string? token);
|
RenewRefreshTokenAsync(string? token);
|
||||||
|
@ -16,6 +16,12 @@
|
|||||||
"User": "",
|
"User": "",
|
||||||
"Password": ""
|
"Password": ""
|
||||||
},
|
},
|
||||||
|
"Authentication": {
|
||||||
|
"Google": {
|
||||||
|
"ClientId": "",
|
||||||
|
"ClientSecret": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"Jwt": {
|
"Jwt": {
|
||||||
"Key": "Secret which will never be exposed",
|
"Key": "Secret which will never be exposed",
|
||||||
"Audience": "Application URL",
|
"Audience": "Application URL",
|
||||||
|
@ -7,14 +7,21 @@
|
|||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Host=localhost;Database=auto.bus;Username=postgres;Password=postgres;"
|
"DefaultConnection": "host=localhost;database=auto.bus;user id=postgres;password=postgres;Include Error Detail = true"
|
||||||
},
|
},
|
||||||
|
"ApplicationName": "auto.bus",
|
||||||
"SmtpCredentials": {
|
"SmtpCredentials": {
|
||||||
"Host": "",
|
"Host": "",
|
||||||
"Port": "",
|
"Port": "",
|
||||||
"User": "",
|
"User": "",
|
||||||
"Password": ""
|
"Password": ""
|
||||||
},
|
},
|
||||||
|
"Authentication": {
|
||||||
|
"Google": {
|
||||||
|
"ClientId": "",
|
||||||
|
"ClientSecret": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"Jwt": {
|
"Jwt": {
|
||||||
"Key": "Secret which will never be exposed",
|
"Key": "Secret which will never be exposed",
|
||||||
"Audience": "Application URL",
|
"Audience": "Application URL",
|
||||||
|
6
SharedModels/Requests/GoogleAuthenticationRequest.cs
Normal file
6
SharedModels/Requests/GoogleAuthenticationRequest.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace SharedModels.Requests;
|
||||||
|
|
||||||
|
public class GoogleAuthenticationRequest
|
||||||
|
{
|
||||||
|
public string IdToken { get; set; } = null!;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user