diff --git a/Devnot.Mentor.Api/ActionFilters/TokenAuthentication.cs b/Devnot.Mentor.Api/ActionFilters/TokenAuthentication.cs index 489c7e3..f6da6b9 100644 --- a/Devnot.Mentor.Api/ActionFilters/TokenAuthentication.cs +++ b/Devnot.Mentor.Api/ActionFilters/TokenAuthentication.cs @@ -54,7 +54,7 @@ public override void OnActionExecuting(ActionExecutingContext context) context.HttpContext.User = claimsPrincipal; } - catch (Exception ex) + catch (Exception) { context.Result = new UnauthorizedObjectResult(new ErrorApiResponse(ResultMessage.InvalidToken)); } diff --git a/Devnot.Mentor.Api/Configuration/appsettings.development.json b/Devnot.Mentor.Api/Configuration/appsettings.development.json index 892f393..dcfcbe9 100644 --- a/Devnot.Mentor.Api/Configuration/appsettings.development.json +++ b/Devnot.Mentor.Api/Configuration/appsettings.development.json @@ -22,4 +22,4 @@ "UpdatePasswordWebPageUrl": "http://subdomain.devnot.com/sifreyi-yenile", "SecurityKeyExpiryFromHours": 24 } -} +} \ No newline at end of file diff --git a/Devnot.Mentor.Api/Controllers/AuthController.cs b/Devnot.Mentor.Api/Controllers/AuthController.cs new file mode 100644 index 0000000..638200c --- /dev/null +++ b/Devnot.Mentor.Api/Controllers/AuthController.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using DevnotMentor.Api.Services.Interfaces; +using DevnotMentor.Api.Utilities.OAuth; +using Microsoft.AspNetCore.Mvc; + +namespace DevnotMentor.Api.Controllers +{ + public class AuthController : BaseController + { + private readonly IUserService _userService; + + public AuthController(IUserService userService) + { + _userService = userService; + } + + [Route("/auth/github")] + [HttpPost] + public async Task GitHubAsync([FromBody] string accesToken) + { + var oAuthGitHubUser = await OAuthService.GetOAuthGitHubUserAsync(accesToken); + var githubSignInResponse = await _userService.SignInAsync(oAuthGitHubUser); + + return githubSignInResponse.Success ? Success(githubSignInResponse) : BadRequest(); + } + + [Route("/auth/google")] + [HttpPost] + public async Task GoogleAsync([FromBody] string accesToken) + { + var oAuthGoogleUser = await OAuthService.GetOAuthGoogleUserAsync(accesToken); + var googleSignInResponse = await _userService.SignInAsync(oAuthGoogleUser); + + return googleSignInResponse.Success ? Success(googleSignInResponse) : BadRequest(); + } + } +} \ No newline at end of file diff --git a/Devnot.Mentor.Api/Controllers/UserController.cs b/Devnot.Mentor.Api/Controllers/UserController.cs index db302ec..c51d764 100644 --- a/Devnot.Mentor.Api/Controllers/UserController.cs +++ b/Devnot.Mentor.Api/Controllers/UserController.cs @@ -1,13 +1,12 @@ using System.Threading.Tasks; using DevnotMentor.Api.ActionFilters; -using DevnotMentor.Api.CustomEntities.Request.UserRequest; using DevnotMentor.Api.Helpers.Extensions; using DevnotMentor.Api.Services.Interfaces; using Microsoft.AspNetCore.Mvc; namespace DevnotMentor.Api.Controllers { - [ApiController] + [ServiceFilter(typeof(TokenAuthentication)), ApiController, Route("users"),] public class UserController : BaseController { private readonly IUserService userService; @@ -17,62 +16,11 @@ public UserController(IUserService userService) this.userService = userService; } - [HttpPost] - [Route("/users/login")] - public async Task Login(UserLoginRequest request) + [HttpGet("me")] + public async Task GetMe() { - var result = await userService.LoginAsync(request); - - return result.Success ? Success(result) : BadRequest(result); - } - - [HttpPost] - [Route("/users/register")] - public async Task Register([FromForm] RegisterUserRequest request) - { - var result = await userService.RegisterAsync(request); - - return result.Success ? Success(result) : BadRequest(result); - } - - [HttpPost] - [Route("/users/change-password")] - [ServiceFilter(typeof(TokenAuthentication))] - public async Task ChangePassword([FromBody] UpdatePasswordRequest request) - { - request.UserId = User.Claims.GetUserId(); - - var result = await userService.ChangePasswordAsync(request); - - return result.Success ? Success(result) : BadRequest(result); - } - - [HttpPatch] - [Route("/users")] - [ServiceFilter(typeof(TokenAuthentication))] - public async Task UpdateUser([FromForm] UpdateUserRequest request) - { - request.UserId = User.Claims.GetUserId(); - - var result = await userService.UpdateAsync(request); - - return result.Success ? Success(result) : BadRequest(result); - } - - [Route("/users/{email}/remind-password")] - [HttpGet] - public async Task RemindPassword([FromRoute] string email) - { - var result = await userService.RemindPasswordAsync(email); - - return result.Success ? Success(result) : BadRequest(result); - } - - [HttpPost] - [Route("/users/me/remind-password-complete")] - public async Task RemindPasswordCompleteAsync(CompleteRemindPasswordRequest request) - { - var result = await userService.RemindPasswordCompleteAsync(request); + var authenticatedUserId = User.Claims.GetUserId(); + var result = await userService.GetByUserIdAsync(authenticatedUserId); return result.Success ? Success(result) : BadRequest(result); } diff --git a/Devnot.Mentor.Api/CustomEntities/Auth/OAuthGitHubUser.cs b/Devnot.Mentor.Api/CustomEntities/Auth/OAuthGitHubUser.cs new file mode 100644 index 0000000..78b939b --- /dev/null +++ b/Devnot.Mentor.Api/CustomEntities/Auth/OAuthGitHubUser.cs @@ -0,0 +1,24 @@ +using System; +using System.Threading.Tasks; +using DevnotMentor.Api.Entities; +using DevnotMentor.Api.Repositories.Interfaces; + +namespace DevnotMentor.Api.CustomEntities.Auth +{ + public class OAuthGitHubUser : OAuthUser + { + public OAuthGitHubUser() : base(OAuthType.GitHub) + { + } + + public override async Task GetUserFromDatabaseAsync(IUserRepository repository) + { + if (repository is null) + { + throw new NullReferenceException($"{repository.GetType().FullName} was null."); + } + + return await repository.GetByGitHubIdAsync(base.Id); + } + } +} diff --git a/Devnot.Mentor.Api/CustomEntities/Auth/OAuthGoogleUser.cs b/Devnot.Mentor.Api/CustomEntities/Auth/OAuthGoogleUser.cs new file mode 100644 index 0000000..e4ac140 --- /dev/null +++ b/Devnot.Mentor.Api/CustomEntities/Auth/OAuthGoogleUser.cs @@ -0,0 +1,24 @@ +using System; +using System.Threading.Tasks; +using DevnotMentor.Api.Entities; +using DevnotMentor.Api.Repositories.Interfaces; + +namespace DevnotMentor.Api.CustomEntities.Auth +{ + public class OAuthGoogleUser : OAuthUser + { + public OAuthGoogleUser() : base(OAuthType.Google) + { + } + + public override async Task GetUserFromDatabaseAsync(IUserRepository repository) + { + if (repository is null) + { + throw new NullReferenceException($"{repository.GetType().FullName} was null."); + } + + return await repository.GetByGoogleIdAsync(base.Id); + } + } +} diff --git a/Devnot.Mentor.Api/CustomEntities/Auth/OAuthType.cs b/Devnot.Mentor.Api/CustomEntities/Auth/OAuthType.cs new file mode 100644 index 0000000..6950659 --- /dev/null +++ b/Devnot.Mentor.Api/CustomEntities/Auth/OAuthType.cs @@ -0,0 +1,8 @@ +namespace DevnotMentor.Api.CustomEntities.Auth +{ + public enum OAuthType : int + { + Google, + GitHub + } +} diff --git a/Devnot.Mentor.Api/CustomEntities/Auth/OAuthUser.cs b/Devnot.Mentor.Api/CustomEntities/Auth/OAuthUser.cs new file mode 100644 index 0000000..c66c4f5 --- /dev/null +++ b/Devnot.Mentor.Api/CustomEntities/Auth/OAuthUser.cs @@ -0,0 +1,37 @@ +using System; +using System.Threading.Tasks; +using DevnotMentor.Api.Entities; +using DevnotMentor.Api.Repositories.Interfaces; + +namespace DevnotMentor.Api.CustomEntities.Auth +{ + public abstract class OAuthUser + { + protected OAuthUser(OAuthType providerType) + { + OAuthProviderType = providerType; + } + + /// + /// Provider ID + /// + public string Id { get; set; } + public string FullName { get; set; } + public string UserName { get; set; } + public string Email { get; set; } + public bool EmailConfirmed { get; set; } + public string ProfilePictureUrl { get; set; } + public OAuthType OAuthProviderType { get; private set; } + + /// + /// Get User by Provider + /// + /// + public abstract Task GetUserFromDatabaseAsync(IUserRepository repository); + + public void SetRandomUsername() + { + this.UserName = Guid.NewGuid().ToString().Split('-')[0]; + } + } +} \ No newline at end of file diff --git a/Devnot.Mentor.Api/CustomEntities/Auth/Response/OAuthGitHubEmailResponse.cs b/Devnot.Mentor.Api/CustomEntities/Auth/Response/OAuthGitHubEmailResponse.cs new file mode 100644 index 0000000..07964a5 --- /dev/null +++ b/Devnot.Mentor.Api/CustomEntities/Auth/Response/OAuthGitHubEmailResponse.cs @@ -0,0 +1,9 @@ +namespace DevnotMentor.Api.CustomEntities.Auth.Response +{ + public class OAuthGitHubEmailResponse + { + public string email { get; set; } + public bool primary { get; set; } + public bool verified { get; set; } + } +} \ No newline at end of file diff --git a/Devnot.Mentor.Api/CustomEntities/Auth/Response/OAuthGitHubResponse.cs b/Devnot.Mentor.Api/CustomEntities/Auth/Response/OAuthGitHubResponse.cs new file mode 100644 index 0000000..2555bdd --- /dev/null +++ b/Devnot.Mentor.Api/CustomEntities/Auth/Response/OAuthGitHubResponse.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace DevnotMentor.Api.CustomEntities.Auth.Response +{ + public class OAuthGitHubResponse + { + public string id { get; set; } + public string name { get; set; } + public string login { get; set; } + public string avatar_url { get; set; } + public List Emails { get; set; } + + public OAuthGitHubUser MapToOAuthGitHubUser() + { + var primaryEmail = Emails.Find(x => x.primary == true); + + return new OAuthGitHubUser() + { + Email = primaryEmail?.email, + Id = id, + FullName = name, + ProfilePictureUrl = avatar_url, + UserName = login, + EmailConfirmed = primaryEmail is null ? false : primaryEmail.verified + }; + } + } +} diff --git a/Devnot.Mentor.Api/CustomEntities/Auth/Response/OAuthGoogleResponse.cs b/Devnot.Mentor.Api/CustomEntities/Auth/Response/OAuthGoogleResponse.cs new file mode 100644 index 0000000..07c3b30 --- /dev/null +++ b/Devnot.Mentor.Api/CustomEntities/Auth/Response/OAuthGoogleResponse.cs @@ -0,0 +1,25 @@ +using System; + +namespace DevnotMentor.Api.CustomEntities.Auth.Response +{ + public class OAuthGoogleResponse + { + public string id { get; set; } + public string name { get; set; } + public string email { get; set; } + public string picture { get; set; } + + public OAuthGoogleUser MapToOAuthGoogleUser() + { + return new OAuthGoogleUser() + { + Email = email, + Id = id, + FullName = name, + ProfilePictureUrl = picture, + EmailConfirmed = (!String.IsNullOrEmpty(email)), + UserName = Guid.NewGuid().ToString().Split('-')[0] + }; + } + } +} diff --git a/Devnot.Mentor.Api/CustomEntities/Dto/UserDto.cs b/Devnot.Mentor.Api/CustomEntities/Dto/UserDto.cs index 51f4697..69502ac 100644 --- a/Devnot.Mentor.Api/CustomEntities/Dto/UserDto.cs +++ b/Devnot.Mentor.Api/CustomEntities/Dto/UserDto.cs @@ -13,12 +13,8 @@ public UserDto() public int Id { get; set; } public string UserName { get; set; } - public string Name { get; set; } - public string SurName { get; set; } - public string ProfileImageUrl { get; set; } - public bool? UserNameConfirmed { get; set; } - public int? UserState { get; set; } - public string ProfileUrl { get; set; } + public string FullName { get; set; } + public string ProfilePictureUrl { get; set; } public bool IsMentee => Mentee.Any(); public bool IsMentor => Mentor.Any(); diff --git a/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/CompleteRemindPasswordRequest.cs b/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/CompleteRemindPasswordRequest.cs deleted file mode 100644 index ea316f7..0000000 --- a/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/CompleteRemindPasswordRequest.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; - -namespace DevnotMentor.Api.CustomEntities.Request.UserRequest -{ - public class CompleteRemindPasswordRequest - { - [Required] - public string Password { get; set; } - [Required] - public Guid SecurityKey { get; set; } - } -} diff --git a/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/RegisterUserRequest.cs b/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/RegisterUserRequest.cs deleted file mode 100644 index ae72460..0000000 --- a/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/RegisterUserRequest.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using Microsoft.AspNetCore.Http; - -namespace DevnotMentor.Api.CustomEntities.Request.UserRequest -{ - public class RegisterUserRequest - { - [Required] - public string UserName { get; set; } - - [Required] - public string Email { get; set; } - - [Required] - public string Password { get; set; } - - [Required] - public string Name { get; set; } - - [Required] - public string SurName { get; set; } - - public string ProfileImageUrl { get; set; } - - [Required] - public IFormFile ProfileImage { get; set; } - } -} diff --git a/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/UpdatePasswordRequest.cs b/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/UpdatePasswordRequest.cs deleted file mode 100644 index 13ac684..0000000 --- a/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/UpdatePasswordRequest.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace DevnotMentor.Api.CustomEntities.Request.UserRequest -{ - public class UpdatePasswordRequest - { - public int UserId { get; set; } - - [Required] - public string LastPassword { get; set; } - [Required] - public string NewPassword { get; set; } - } -} diff --git a/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/UpdateUserRequest.cs b/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/UpdateUserRequest.cs index 82c353b..41c01c0 100644 --- a/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/UpdateUserRequest.cs +++ b/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/UpdateUserRequest.cs @@ -1,20 +1,12 @@ using System.ComponentModel.DataAnnotations; -using Microsoft.AspNetCore.Http; namespace DevnotMentor.Api.CustomEntities.Request.UserRequest { public class UpdateUserRequest { - public int UserId { get; set; } - [Required] - public string Name { get; set; } - + public string FullName { get; set; } [Required] - public string SurName { get; set; } - - public string ProfileImageUrl { get; set; } - - public IFormFile ProfileImage { get; set; } + public string Email { get; set; } } } diff --git a/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/UserLoginRequest.cs b/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/UserLoginRequest.cs deleted file mode 100644 index cfd153e..0000000 --- a/Devnot.Mentor.Api/CustomEntities/Request/UserRequest/UserLoginRequest.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace DevnotMentor.Api.CustomEntities.Request.UserRequest -{ - public class UserLoginRequest - { - [Required] - public string UserName { get; set; } - - [Required] - public string Password { get; set; } - } -} diff --git a/Devnot.Mentor.Api/CustomEntities/Response/UserResponse/UserLoginResponse.cs b/Devnot.Mentor.Api/CustomEntities/Response/UserResponse/UserLoginResponse.cs deleted file mode 100644 index 56ca9f2..0000000 --- a/Devnot.Mentor.Api/CustomEntities/Response/UserResponse/UserLoginResponse.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using DevnotMentor.Api.CustomEntities.Dto; - -namespace DevnotMentor.Api.CustomEntities.Response.UserResponse -{ - public class UserLoginResponse - { - public UserLoginResponse(UserDto user, string token, DateTime? tokenExpiryDate) - { - User = user; - Token = token; - TokenExpiryDate = tokenExpiryDate; - } - - public UserDto User { get; set; } - public string Token { get; set; } - public DateTime? TokenExpiryDate { get; set; } - } -} diff --git a/Devnot.Mentor.Api/DevnotMentor.Api.csproj b/Devnot.Mentor.Api/DevnotMentor.Api.csproj index 8d016c6..d0788e5 100644 --- a/Devnot.Mentor.Api/DevnotMentor.Api.csproj +++ b/Devnot.Mentor.Api/DevnotMentor.Api.csproj @@ -10,7 +10,6 @@ - @@ -23,6 +22,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Devnot.Mentor.Api/Entities/MentorApplications.cs b/Devnot.Mentor.Api/Entities/MentorApplications.cs index 5bc62a3..7ad2297 100644 --- a/Devnot.Mentor.Api/Entities/MentorApplications.cs +++ b/Devnot.Mentor.Api/Entities/MentorApplications.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; namespace DevnotMentor.Api.Entities { diff --git a/Devnot.Mentor.Api/Entities/MentorDBContext.cs b/Devnot.Mentor.Api/Entities/MentorDBContext.cs index d0b190d..2977289 100644 --- a/Devnot.Mentor.Api/Entities/MentorDBContext.cs +++ b/Devnot.Mentor.Api/Entities/MentorDBContext.cs @@ -1,15 +1,9 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore; namespace DevnotMentor.Api.Entities { public partial class MentorDBContext : DbContext { - public MentorDBContext() - { - } - public MentorDBContext(DbContextOptions options) : base(options) { @@ -31,15 +25,6 @@ public MentorDBContext(DbContextOptions options) public virtual DbSet Tag { get; set; } public virtual DbSet User { get; set; } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - if (!optionsBuilder.IsConfigured) - { -#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings. - optionsBuilder.UseSqlServer("Server=DESKTOP-8TSS65S;Database=MentorDB;Trusted_Connection=True;MultipleActiveResultSets=true"); - } - } - protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity(entity => @@ -292,34 +277,32 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity(entity => { - entity.Property(e => e.Name) - .HasMaxLength(50) - .IsUnicode(false); + entity.HasKey(p => p.Id); - entity.Property(e => e.Password) - .HasMaxLength(512) - .IsUnicode(false); - - entity.Property(e => e.ProfileImageUrl) - .HasMaxLength(500) - .IsFixedLength(); + entity.HasIndex(p => p.UserName).IsUnique(); + entity.HasIndex(p => p.Email).IsUnique().HasFilter("[Email] IS NOT NULL"); + entity.HasIndex(p => p.GitHubId).IsUnique().HasFilter("[GitHubId] IS NOT NULL"); + entity.HasIndex(p => p.GoogleId).IsUnique().HasFilter("[GoogleId] IS NOT NULL"); - entity.Property(e => e.ProfileUrl) - .HasMaxLength(200) + entity.Property(p => p.GitHubId) + .HasMaxLength(64) .IsUnicode(false); - entity.Property(e => e.SurName) - .HasMaxLength(50) + entity.Property(p => p.GoogleId) + .HasMaxLength(64) .IsUnicode(false); - entity.Property(e => e.Token) - .HasMaxLength(500) + entity.Property(p => p.Email) + .HasMaxLength(254) .IsUnicode(false); - entity.Property(e => e.TokenExpireDate).HasColumnType("datetime"); - entity.Property(e => e.UserName) - .HasMaxLength(100) + .HasMaxLength(39) + .IsUnicode(false) + .IsRequired(true); + + entity.Property(e => e.FullName) + .HasMaxLength(50) .IsUnicode(false); }); diff --git a/Devnot.Mentor.Api/Entities/User.cs b/Devnot.Mentor.Api/Entities/User.cs index e6ba355..71dd682 100644 --- a/Devnot.Mentor.Api/Entities/User.cs +++ b/Devnot.Mentor.Api/Entities/User.cs @@ -12,19 +12,14 @@ public User() } public int Id { get; set; } + public string GitHubId { get; set; } + public string GoogleId { get; set; } public string UserName { get; set; } public string Email { get; set; } - public string Password { get; set; } - public string Name { get; set; } - public string SurName { get; set; } - public string ProfileImageUrl { get; set; } - public bool? UserNameConfirmed { get; set; } - public int? UserState { get; set; } - public string Token { get; set; } - public DateTime? TokenExpireDate { get; set; } - public string ProfileUrl { get; set; } - public DateTime? SecurityKeyExpiryDate { get; set; } - public Guid? SecurityKey { get; set; } + public string FullName { get; set; } + public string ProfilePictureUrl { get; set; } + public bool EmailConfirmed { get; set; } + public DateTime CreatedAt { get; private set; } = DateTime.Now; public virtual ICollection Mentee { get; set; } public virtual ICollection Mentor { get; set; } diff --git a/Devnot.Mentor.Api/Helpers/Extensions/ServiceCollectionExtensions.cs b/Devnot.Mentor.Api/Helpers/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..2090c1e --- /dev/null +++ b/Devnot.Mentor.Api/Helpers/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,57 @@ +using System; +using DevnotMentor.Api.Services.Interfaces; +using Microsoft.Extensions.DependencyInjection; +using DevnotMentor.Api.ActionFilters; +using DevnotMentor.Api.Configuration.Environment; +using DevnotMentor.Api.Services; +using DevnotMentor.Api.Utilities.Email; +using DevnotMentor.Api.Utilities.Security.Token; +using DevnotMentor.Api.Configuration.Context; +using DevnotMentor.Api.Repositories.Interfaces; +using DevnotMentor.Api.Repositories; +using DevnotMentor.Api.Utilities.Email.SmtpMail; +using DevnotMentor.Api.Utilities.Security.Token.Jwt; + +namespace DevnotMentor.Api.Helpers.Extensions +{ + public static class ServiceCollectionExtensions + { + public static IServiceCollection AddCustomServices(this IServiceCollection services) + { + + services.AddSingleton(); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + services.AddScoped(); + //services.AddScoped(); + + services.AddSingleton(); + //services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddCustomSwagger(); + return services; + } + public static IServiceCollection AddRepositories(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/Devnot.Mentor.Api/Helpers/MappingProfile.cs b/Devnot.Mentor.Api/Helpers/MappingProfile.cs index 78497b2..a6fc2a3 100644 --- a/Devnot.Mentor.Api/Helpers/MappingProfile.cs +++ b/Devnot.Mentor.Api/Helpers/MappingProfile.cs @@ -1,9 +1,9 @@ using AutoMapper; +using DevnotMentor.Api.CustomEntities.Auth; using DevnotMentor.Api.CustomEntities.Dto; using DevnotMentor.Api.CustomEntities.Request.MenteeRequest; using DevnotMentor.Api.CustomEntities.Request.MentorRequest; using DevnotMentor.Api.Entities; -using DevnotMentor.Api.CustomEntities.Request.UserRequest; namespace DevnotMentor.Api.Helpers { @@ -13,10 +13,28 @@ public MappingProfile() { CreateMap(); CreateMap(); + CreateMap(); + + CreateMap() + .ForMember(user => user.GitHubId, opt => // if OAuthUser type is GitHub, map Id to GitHubId + { + opt.Condition(oAuthUser => oAuthUser.OAuthProviderType == OAuthType.GitHub); + opt.MapFrom(oAuthUser => oAuthUser.Id); + }) + .ForMember(user => user.GoogleId, opt => // if OAuthUser type is Google, map Id to GoogleId + { + opt.Condition(oAuthUser => oAuthUser.OAuthProviderType == OAuthType.Google); + opt.MapFrom(oAuthUser => oAuthUser.Id); + }) + .ForMember(user => user.Id, opt => opt.Ignore()); + + CreateMap(); + CreateMap(); CreateMap(); + CreateMap() .ForMember(dest => dest.MentorTags, opt => opt.Ignore()) .ForMember(dest => dest.MentorLinks, opt => opt.Ignore()) @@ -27,9 +45,6 @@ public MappingProfile() .ForMember(dest => dest.MenteeLinks, opt => opt.Ignore()) .ReverseMap(); - - CreateMap(); - CreateMap(); CreateMap(); CreateMap(); diff --git a/Devnot.Mentor.Api/Repositories/Interfaces/IRepository.cs b/Devnot.Mentor.Api/Repositories/Interfaces/IRepository.cs index 427763b..4db6882 100644 --- a/Devnot.Mentor.Api/Repositories/Interfaces/IRepository.cs +++ b/Devnot.Mentor.Api/Repositories/Interfaces/IRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace DevnotMentor.Api.Repositories.Interfaces { diff --git a/Devnot.Mentor.Api/Repositories/Interfaces/IUserRepository.cs b/Devnot.Mentor.Api/Repositories/Interfaces/IUserRepository.cs index dc68860..8458b7f 100644 --- a/Devnot.Mentor.Api/Repositories/Interfaces/IUserRepository.cs +++ b/Devnot.Mentor.Api/Repositories/Interfaces/IUserRepository.cs @@ -1,19 +1,18 @@ using DevnotMentor.Api.Entities; -using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; namespace DevnotMentor.Api.Repositories.Interfaces { public interface IUserRepository : IRepository { + Task GetByGitHubIdAsync(object identifier); + Task GetByGoogleIdAsync(object identifier); Task GetByIdAsync(int id); + Task GetByIdIncludeMenteeMentorAsync(int id); Task GetByUserNameAsync(string userName); - Task GetAsync(string userName, string hashedPassword); - Task GetAsync(int userId, string hashedPassword); + Task AnyByUserNameAsync(string userName); + Task AnyByEmailAsync(string email); Task GetByEmailAsync(string email); - Task GetAsync(Guid securityKey); Task IsExistsAsync(int id); } } diff --git a/Devnot.Mentor.Api/Repositories/MenteeRepository.cs b/Devnot.Mentor.Api/Repositories/MenteeRepository.cs index ec80298..caa8dab 100644 --- a/Devnot.Mentor.Api/Repositories/MenteeRepository.cs +++ b/Devnot.Mentor.Api/Repositories/MenteeRepository.cs @@ -33,7 +33,7 @@ public Task> SearchAsync(SearchRequest request) if (!string.IsNullOrEmpty(request.FullName)) { - queryableMentee = queryableMentee.Where(mentee => (mentee.User.Name + " " + mentee.User.SurName).Contains(request.FullName)); + queryableMentee = queryableMentee.Where(mentee => (mentee.User.FullName).Contains(request.FullName)); } if (!string.IsNullOrEmpty(request.Title)) diff --git a/Devnot.Mentor.Api/Repositories/MentorRepository.cs b/Devnot.Mentor.Api/Repositories/MentorRepository.cs index b06cd45..e9a5043 100644 --- a/Devnot.Mentor.Api/Repositories/MentorRepository.cs +++ b/Devnot.Mentor.Api/Repositories/MentorRepository.cs @@ -30,7 +30,7 @@ public Task> SearchAsync(SearchRequest request) if (!string.IsNullOrEmpty(request.FullName)) { - queryableMentor = queryableMentor.Where(mentor => (mentor.User.Name + " " + mentor.User.SurName).Contains(request.FullName)); + queryableMentor = queryableMentor.Where(mentor => (mentor.User.FullName).Contains(request.FullName)); } if (!string.IsNullOrEmpty(request.Title)) diff --git a/Devnot.Mentor.Api/Repositories/UserRepository.cs b/Devnot.Mentor.Api/Repositories/UserRepository.cs index 2acbec9..06ddc42 100644 --- a/Devnot.Mentor.Api/Repositories/UserRepository.cs +++ b/Devnot.Mentor.Api/Repositories/UserRepository.cs @@ -1,8 +1,6 @@ using DevnotMentor.Api.Entities; using DevnotMentor.Api.Repositories.Interfaces; using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -18,34 +16,32 @@ public async Task GetByIdAsync(int id) { return await DbContext.User.Where(i => i.Id == id).FirstOrDefaultAsync(); } - - public async Task GetAsync(string userName, string hashedPassword) + + public async Task GetByIdIncludeMenteeMentorAsync(int id) { - return await DbContext - .User - .Where(u => u.UserName == userName && u.Password == hashedPassword) + return await DbContext.User .Include(user => user.Mentee) .ThenInclude(mentee => mentee.MenteeTags) .ThenInclude(menteeTag => menteeTag.Tag) .Include(user => user.Mentor) .ThenInclude(mentor => mentor.MentorTags) .ThenInclude(mentorTag => mentorTag.Tag) - .FirstOrDefaultAsync(); + .FirstOrDefaultAsync(i => i.Id == id); } - public async Task GetAsync(int userId, string hashedPassword) + public async Task AnyByUserNameAsync(string userName) { - return await DbContext.User.Where(i => i.Id == userId && i.Password == hashedPassword).FirstOrDefaultAsync(); + return await DbContext.User.Where(i => i.UserName == userName).AnyAsync(); } - public async Task GetByEmailAsync(string email) + public async Task AnyByEmailAsync(string email) { - return await DbContext.User.Where(i => i.Email == email).FirstOrDefaultAsync(); + return await DbContext.User.Where(i => i.Email == email).AnyAsync(); } - public async Task GetAsync(Guid securityKey) + public async Task GetByEmailAsync(string email) { - return await DbContext.User.Where(i => i.SecurityKey == securityKey).FirstOrDefaultAsync(); + return await DbContext.User.Where(i => i.Email == email).FirstOrDefaultAsync(); } public async Task IsExistsAsync(int id) @@ -57,5 +53,15 @@ public async Task GetByUserNameAsync(string userName) { return await DbContext.User.Where(u => u.UserName == userName).FirstOrDefaultAsync(); } + + public async Task GetByGitHubIdAsync(object identifier) + { + return await DbContext.User.Where(u => u.GitHubId == identifier.ToString()).FirstOrDefaultAsync(); + } + + public async Task GetByGoogleIdAsync(object identifier) + { + return await DbContext.User.Where(u => u.GoogleId == identifier.ToString()).FirstOrDefaultAsync(); + } } } diff --git a/Devnot.Mentor.Api/Services/Interfaces/IUserService.cs b/Devnot.Mentor.Api/Services/Interfaces/IUserService.cs index 7a9378d..28cf745 100644 --- a/Devnot.Mentor.Api/Services/Interfaces/IUserService.cs +++ b/Devnot.Mentor.Api/Services/Interfaces/IUserService.cs @@ -1,17 +1,14 @@ using System.Threading.Tasks; using DevnotMentor.Api.Common.Response; -using DevnotMentor.Api.CustomEntities.Request.UserRequest; -using DevnotMentor.Api.CustomEntities.Response.UserResponse; +using DevnotMentor.Api.CustomEntities.Auth; +using DevnotMentor.Api.CustomEntities.Dto; +using DevnotMentor.Api.Utilities.Security.Token; namespace DevnotMentor.Api.Services.Interfaces { public interface IUserService { - Task> LoginAsync(UserLoginRequest request); - Task RegisterAsync(RegisterUserRequest request); - Task ChangePasswordAsync(UpdatePasswordRequest request); - Task UpdateAsync(UpdateUserRequest request); - Task RemindPasswordAsync(string email); - Task RemindPasswordCompleteAsync(CompleteRemindPasswordRequest request); + Task> SignInAsync(OAuthUser oAuthUser); + Task> GetByUserIdAsync(int userId); } } diff --git a/Devnot.Mentor.Api/Services/UserService.cs b/Devnot.Mentor.Api/Services/UserService.cs index b81f8f3..4575dc9 100644 --- a/Devnot.Mentor.Api/Services/UserService.cs +++ b/Devnot.Mentor.Api/Services/UserService.cs @@ -3,191 +3,69 @@ using DevnotMentor.Api.Entities; using DevnotMentor.Api.Repositories.Interfaces; using DevnotMentor.Api.Services.Interfaces; -using DevnotMentor.Api.Utilities.Email; -using DevnotMentor.Api.Utilities.Security.Hash; using DevnotMentor.Api.Utilities.Security.Token; -using System; -using System.Collections.Generic; using System.Threading.Tasks; using DevnotMentor.Api.Common.Response; using DevnotMentor.Api.Configuration.Context; +using DevnotMentor.Api.CustomEntities.Auth; using DevnotMentor.Api.CustomEntities.Dto; -using DevnotMentor.Api.CustomEntities.Request.UserRequest; -using DevnotMentor.Api.CustomEntities.Response.UserResponse; -using DevnotMentor.Api.Utilities.File; namespace DevnotMentor.Api.Services { - //TODO: Aynı username ile kayıt yapılabiliyor - public class UserService : BaseService, IUserService { private readonly IUserRepository userRepository; - private readonly IHashService hashService; private readonly ITokenService tokenService; - private readonly IMailService mailService; - - private readonly IFileService fileService; public UserService( IMapper mapper, - ITokenService tokenService, - IHashService hashService, - IMailService mailService, IUserRepository userRepository, ILoggerRepository loggerRepository, - IFileService fileService, + ITokenService tokenService, IDevnotConfigurationContext devnotConfigurationContext) : base(mapper, loggerRepository, devnotConfigurationContext) { this.tokenService = tokenService; - this.hashService = hashService; - this.mailService = mailService; this.userRepository = userRepository; - this.fileService = fileService; - } - - public async Task ChangePasswordAsync(UpdatePasswordRequest request) - { - string hashedLastPassword = hashService.CreateHash(request.LastPassword); - - var currentUser = await userRepository.GetAsync(request.UserId, hashedLastPassword); - - if (currentUser == null) - { - return new ErrorApiResponse(ResultMessage.NotFoundUser); - } - - currentUser.Password = hashService.CreateHash(request.NewPassword); - - userRepository.Update(currentUser); - - return new SuccessApiResponse(ResultMessage.Success); - } - - public async Task> LoginAsync(UserLoginRequest request) - { - var hashedPassword = hashService.CreateHash(request.Password); - - var user = await userRepository.GetAsync(request.UserName, hashedPassword); - - if (user == null) - { - return new ErrorApiResponse(data: null, ResultMessage.InvalidUserNameOrPassword); - } - - if (!user.UserNameConfirmed.HasValue || !user.UserNameConfirmed.Value) - { - return new ErrorApiResponse(data: null, ResultMessage.UserNameIsNotValidated); - } - - var tokenData = tokenService.CreateToken(user.Id, user.UserName); - - user.Token = tokenData.Token; - user.TokenExpireDate = tokenData.ExpiredDate; - - var mappedUser = mapper.Map(user); - - var loginResponse = new UserLoginResponse(mappedUser, user.Token, user.TokenExpireDate); - - return new SuccessApiResponse(data: loginResponse, ResultMessage.Success); } - public async Task RegisterAsync(RegisterUserRequest request) + private async Task CreateUserForOAuthUserAsync(OAuthUser oAuthUser) { - var checkFileResult = await fileService.InsertProfileImageAsync(request.ProfileImage); - - if (!checkFileResult.IsSuccess) - { - return new ErrorApiResponse(data: default, checkFileResult.ErrorMessage); - } - - request.ProfileImageUrl = checkFileResult.RelativeFilePath; - request.Password = hashService.CreateHash(request.Password); - - userRepository.Create(mapper.Map(request)); - - return new SuccessApiResponse(ResultMessage.Success); - } + var anySimilarUser = await userRepository.AnyByUserNameAsync(oAuthUser.UserName); - public async Task RemindPasswordAsync(string email) - { - if (String.IsNullOrWhiteSpace(email)) + if (anySimilarUser) { - return new ErrorApiResponse(ResultMessage.InvalidModel); + oAuthUser.SetRandomUsername(); } - var currentUser = await userRepository.GetByEmailAsync(email); + anySimilarUser = await userRepository.AnyByEmailAsync(oAuthUser.Email); - if (currentUser == null) + if (anySimilarUser) { - return new ErrorApiResponse(ResultMessage.NotFoundUser); + oAuthUser.Email = null; + oAuthUser.EmailConfirmed = false; } - currentUser.SecurityKey = Guid.NewGuid(); - currentUser.SecurityKeyExpiryDate = DateTime.Now.AddHours(devnotConfigurationContext.SecurityKeyExpiryFromHours); - - userRepository.Update(currentUser); - - await SendRemindPasswordMailAsync(currentUser); - - return new SuccessApiResponse(ResultMessage.Success); - } - - // TODO: İlerleyen zamanlarda template olarak veri tabanı ya da dosyadan okunulacak. - private async Task SendRemindPasswordMailAsync(User user) - { - var to = new List { user.Email }; - string subject = "Devnot Mentor Programı | Parola Sıfırlama İsteği"; - string remindPasswordUrl = $"{devnotConfigurationContext.UpdatePasswordWebPageUrl}?securityKey={user.SecurityKey}"; - string body = $"Merhaba {user.Name} {user.SurName}, buradan parolanızı sıfırlayabilirsiniz."; + var user = mapper.Map(oAuthUser); - await mailService.SendEmailAsync(to, subject, body); + return userRepository.Create(user); } - public async Task UpdateAsync(UpdateUserRequest request) + public async Task> SignInAsync(OAuthUser oAuthUser) { - var currentUser = await userRepository.GetByIdAsync(request.UserId); + var user = await oAuthUser.GetUserFromDatabaseAsync(userRepository); - if (request.ProfileImage != null) + if (user is null) { - var checkUploadedImageFileResult = await fileService.InsertProfileImageAsync(request.ProfileImage); - - if (!checkUploadedImageFileResult.IsSuccess) - { - return new ErrorApiResponse(data: default, checkUploadedImageFileResult.ErrorMessage); - } - - currentUser.ProfileImageUrl = checkUploadedImageFileResult.RelativeFilePath; + user = await CreateUserForOAuthUserAsync(oAuthUser); } - currentUser.Name = request.Name; - currentUser.SurName = request.SurName; - - userRepository.Update(currentUser); - - return new SuccessApiResponse(ResultMessage.Success); + return new SuccessApiResponse(data: tokenService.CreateToken(user.Id, user.UserName), ResultMessage.Success); } - public async Task RemindPasswordCompleteAsync(CompleteRemindPasswordRequest request) + public async Task> GetByUserIdAsync(int userId) { - var currentUser = await userRepository.GetAsync(request.SecurityKey); - - if (currentUser == null) - { - return new ErrorApiResponse(ResultMessage.InvalidSecurityKey); - } - - if (currentUser.SecurityKeyExpiryDate < DateTime.Now) - { - return new ErrorApiResponse(ResultMessage.SecurityKeyExpiryDateAlreadyExpired); - } - - currentUser.SecurityKey = null; - currentUser.Password = hashService.CreateHash(request.Password); - - userRepository.Update(currentUser); - - return new SuccessApiResponse(ResultMessage.Success); + var user = await userRepository.GetByIdIncludeMenteeMentorAsync(userId); + return new SuccessApiResponse(data: mapper.Map(user), ResultMessage.Success); } } } diff --git a/Devnot.Mentor.Api/Startup.cs b/Devnot.Mentor.Api/Startup.cs index a072238..f244ed3 100644 --- a/Devnot.Mentor.Api/Startup.cs +++ b/Devnot.Mentor.Api/Startup.cs @@ -1,9 +1,5 @@ using System; -using AutoMapper; using DevnotMentor.Api.Entities; -using DevnotMentor.Api.Helpers; -using DevnotMentor.Api.Services; -using DevnotMentor.Api.Services.Interfaces; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; @@ -11,19 +7,9 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using DevnotMentor.Api.ActionFilters; -using DevnotMentor.Api.Utilities.Security.Token; -using DevnotMentor.Api.Configuration.Context; using DevnotMentor.Api.Configuration.Environment; using DevnotMentor.Api.Middlewares; -using DevnotMentor.Api.Utilities.Security.Hash; -using DevnotMentor.Api.Utilities.Security.Hash.Sha256; -using DevnotMentor.Api.Utilities.Email; -using DevnotMentor.Api.Repositories; -using DevnotMentor.Api.Repositories.Interfaces; -using DevnotMentor.Api.Utilities.Email.SmtpMail; -using DevnotMentor.Api.Utilities.File; -using DevnotMentor.Api.Utilities.File.Local; -using DevnotMentor.Api.Utilities.Security.Token.Jwt; +using DevnotMentor.Api.Helpers.Extensions; namespace DevnotMentor.Api { @@ -31,7 +17,7 @@ public class Startup { public Startup(IConfiguration configuration) { - Configuration = configuration; + this.Configuration = configuration; } public IConfiguration Configuration { get; } @@ -40,6 +26,7 @@ public void ConfigureServices(IServiceCollection services) { var connectionString = EnvironmentService.StaticConfiguration["ConnectionStrings:SQLServerConnectionString"]; services.AddDbContext(options => options.UseSqlServer(connectionString)); + services.AddSingleton(); services.AddControllers() .AddNewtonsoftJson(options => @@ -48,36 +35,8 @@ public void ConfigureServices(IServiceCollection services) services.AddAutoMapper(typeof(Startup)); - services.AddSingleton(); - - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.AddScoped(); - services.AddScoped(); - - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - #region Repositories - - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - #endregion + services.AddCustomServices(); + services.AddRepositories(); services.AddCors(options => { @@ -100,8 +59,6 @@ public void ConfigureServices(IServiceCollection services) { options.JsonSerializerOptions.IgnoreNullValues = true; }); - - services.AddCustomSwagger(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) diff --git a/Devnot.Mentor.Api/Utilities/OAuth/OAuthDefaults.cs b/Devnot.Mentor.Api/Utilities/OAuth/OAuthDefaults.cs new file mode 100644 index 0000000..e318e43 --- /dev/null +++ b/Devnot.Mentor.Api/Utilities/OAuth/OAuthDefaults.cs @@ -0,0 +1,12 @@ +namespace DevnotMentor.Api.Utilities.OAuth +{ + public static class OAuthDefaults + { + public static string UserAgent = "DEVNOT MENTOR"; + + public static string GoogleUserInformationEndpoint = "https://www.googleapis.com/oauth2/v2/userinfo"; + + public static string GitHubUserInformationEndpoint = "https://api.github.com/user"; + public static string GitHubUserEmailEndpoint = "https://api.github.com/user/emails"; + } +} \ No newline at end of file diff --git a/Devnot.Mentor.Api/Utilities/OAuth/OAuthService.cs b/Devnot.Mentor.Api/Utilities/OAuth/OAuthService.cs new file mode 100644 index 0000000..7f5ea0c --- /dev/null +++ b/Devnot.Mentor.Api/Utilities/OAuth/OAuthService.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using DevnotMentor.Api.CustomEntities.Auth; +using DevnotMentor.Api.CustomEntities.Auth.Response; +using Newtonsoft.Json; + +namespace DevnotMentor.Api.Utilities.OAuth +{ + public static class OAuthService + { + /// + /// Get provider response as deserialized + /// + /// + /// Acces token which is coming from Client + /// Generic responses + /// Deserialized generic response. Example: , + private static async Task GetOAuthResponseAsDeserializedAsync(string endpoint, string accessToken) + { + HttpClient httpClient = new HttpClient(); + + HttpRequestMessage oauthRequest = new HttpRequestMessage(HttpMethod.Get, endpoint); + oauthRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + oauthRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + oauthRequest.Headers.Add("User-Agent", OAuthDefaults.UserAgent); + + using (HttpResponseMessage oauthResponse = await httpClient.SendAsync(oauthRequest)) + { + oauthRequest.Dispose(); + httpClient.Dispose(); + + var oauthResponseContentAsString = await oauthResponse.Content.ReadAsStringAsync(); + + return oauthResponse.IsSuccessStatusCode + ? JsonConvert.DeserializeObject(oauthResponseContentAsString) + : throw new System.Exception(oauthResponseContentAsString); // todo: return meaningful message for client + }; + } + + public static async Task GetOAuthGitHubUserAsync(string accessToken) + { + var authGitHubResponse = await GetOAuthResponseAsDeserializedAsync( + OAuthDefaults.GitHubUserInformationEndpoint, + accessToken); + + authGitHubResponse.Emails = await GetOAuthResponseAsDeserializedAsync>( + OAuthDefaults.GitHubUserEmailEndpoint, + accessToken); + + return authGitHubResponse.MapToOAuthGitHubUser(); + } + + public static async Task GetOAuthGoogleUserAsync(string accessToken) + { + var authGoogleResponse = await GetOAuthResponseAsDeserializedAsync( + OAuthDefaults.GoogleUserInformationEndpoint, + accessToken); + + return authGoogleResponse.MapToOAuthGoogleUser(); + } + } +} \ No newline at end of file diff --git a/Devnot.Mentor.Api/Utilities/Security/Token/Jwt/JwtTokenService.cs b/Devnot.Mentor.Api/Utilities/Security/Token/Jwt/JwtTokenService.cs index 91b3da9..57ab1c9 100644 --- a/Devnot.Mentor.Api/Utilities/Security/Token/Jwt/JwtTokenService.cs +++ b/Devnot.Mentor.Api/Utilities/Security/Token/Jwt/JwtTokenService.cs @@ -40,7 +40,7 @@ public TokenInfo CreateToken(int userId, string userName) return new TokenInfo { Token = tokenHandler.WriteToken(token), - ExpiredDate = DateTime.Now.AddMinutes(devnotConfigurationContext.JwtSecretExpirationInMinutes) + ExpiryDate = DateTime.Now.AddMinutes(devnotConfigurationContext.JwtSecretExpirationInMinutes) }; } diff --git a/Devnot.Mentor.Api/Utilities/Security/Token/TokenInfo.cs b/Devnot.Mentor.Api/Utilities/Security/Token/TokenInfo.cs index 05caf40..4432d8f 100644 --- a/Devnot.Mentor.Api/Utilities/Security/Token/TokenInfo.cs +++ b/Devnot.Mentor.Api/Utilities/Security/Token/TokenInfo.cs @@ -1,13 +1,10 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace DevnotMentor.Api.Utilities.Security.Token { public class TokenInfo { public string Token { get; set; } - public DateTime ExpiredDate { get; set; } + public DateTime ExpiryDate { get; set; } } }