This commit is contained in:
s426226 2020-12-06 18:31:05 +01:00
parent 008b4bcd81
commit 742b33e6aa
11 changed files with 235 additions and 3 deletions

View File

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Serwer.Infrastructure.DTO;
using Serwer.Infrastructure.Services; using Serwer.Infrastructure.Services;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -17,5 +18,26 @@ namespace Serwer.Api.Controllers
{ {
_userService = userService; _userService = userService;
} }
[HttpPost("Register")]
public async Task<IActionResult> Register(string email, string name, string surname, string login, string password)
{
await _userService.RegisterAsync(email, name, surname, login, password);
return Ok();
}
[HttpPost("SignIn")]
public async Task<IActionResult> SignIn(string login, string password)
{
var user = await _userService.SignInAsync(login, password);
return Ok(user);
}
[HttpGet("Test")]
public IActionResult Test()
{
return NoContent();
}
} }
} }

View File

@ -1,7 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.AspNetCore.HttpsPolicy;
@ -10,10 +13,13 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Serwer.Core.Repositories; using Serwer.Core.Repositories;
using Serwer.Infrastructure.Mappers;
using Serwer.Infrastructure.Repositories; using Serwer.Infrastructure.Repositories;
using Serwer.Infrastructure.Services; using Serwer.Infrastructure.Services;
using Serwer.Infrastructure.Settings;
namespace Serwer.Api namespace Serwer.Api
{ {
@ -29,13 +35,33 @@ namespace Serwer.Api
// This method gets called by the runtime. Use this method to add services to the container. // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddControllers(); services.AddControllers();
services.AddSwaggerGen(c => services.AddSwaggerGen(c =>
{ {
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Serwer.Api", Version = "v1" }); c.SwaggerDoc("v1", new OpenApiInfo { Title = "Serwer.Api", Version = "v1" });
}); });
var jwtSettings = new JwtSettings()
{
Issuer = "PoszukiwaczInc",
ExpiryMinutes = 120,
Key = "Fjjji0Hdsa4$JgrwIO1j678dCelgFymdo"
};
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(c =>
{
c.TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.Key)),
ValidIssuer = jwtSettings.Issuer,
ValidateAudience = false,
ValidateLifetime = true
};
});
services.AddSingleton<IMapper>(AutoMapperConfig.Initialize());
services.AddSingleton<IJwtHandler, JwtHandler>(sp => new JwtHandler(jwtSettings));
services.AddScoped<IUserRepository, UserRepository>(); services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IUserService, UserService>(); services.AddScoped<IUserService, UserService>();
} }
@ -54,6 +80,7 @@ namespace Serwer.Api
app.UseRouting(); app.UseRouting();
app.UseAuthentication();
app.UseAuthorization(); app.UseAuthorization();
app.UseEndpoints(endpoints => app.UseEndpoints(endpoints =>

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serwer.Infrastructure.DTO
{
public class JwtDto
{
public Guid UserId { get; set; }
public string Token { get; set; }
public long Expires { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serwer.Infrastructure.DTO
{
public class SignedUserDto
{
public UserDto User { get; set; }
public JwtDto Jwt { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serwer.Infrastructure.Extentions
{
public static class Extentions
{
public static long ToTimestamp(this DateTime dateTime)
{
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var time = dateTime.Ticks - epoch.Ticks;
return time / TimeSpan.TicksPerSecond;
}
}
}

View File

@ -0,0 +1,14 @@
using Serwer.Infrastructure.DTO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serwer.Infrastructure.Services
{
public interface IJwtHandler
{
JwtDto CreateToken(Guid userId);
}
}

View File

@ -1,4 +1,5 @@
using System; using Serwer.Infrastructure.DTO;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -8,5 +9,7 @@ namespace Serwer.Infrastructure.Services
{ {
public interface IUserService public interface IUserService
{ {
Task RegisterAsync(string email, string name, string surname, string login, string password);
Task<SignedUserDto> SignInAsync(string login, string password);
} }
} }

View File

@ -0,0 +1,55 @@
using Microsoft.IdentityModel.Tokens;
using Serwer.Infrastructure.DTO;
using Serwer.Infrastructure.Extentions;
using Serwer.Infrastructure.Settings;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace Serwer.Infrastructure.Services
{
public class JwtHandler: IJwtHandler
{
private readonly JwtSettings _settings;
public JwtHandler(JwtSettings settings)
{
_settings = settings;
}
public JwtDto CreateToken(Guid userId)
{
var now = DateTime.UtcNow;
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Sub, userId.ToString()),
new Claim(JwtRegisteredClaimNames.UniqueName, userId.ToString()),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, now.ToTimestamp().ToString(), ClaimValueTypes.Integer64)
};
var expires = now.AddMinutes(_settings.ExpiryMinutes);
var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_settings.Key)),
SecurityAlgorithms.HmacSha256);
var jwt = new JwtSecurityToken(
issuer: _settings.Issuer,
claims: claims,
notBefore: now,
expires: expires,
signingCredentials: signingCredentials
);
var token = new JwtSecurityTokenHandler().WriteToken(jwt);
return new JwtDto
{
UserId = userId,
Token = token,
Expires = expires.ToTimestamp()
};
}
}
}

View File

@ -1,4 +1,9 @@
using System; using AutoMapper;
using Serwer.Core.Domain;
using Serwer.Core.Repositories;
using Serwer.Infrastructure.DTO;
using Serwer.Infrastructure.Mappers;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -8,5 +13,46 @@ namespace Serwer.Infrastructure.Services
{ {
public class UserService: IUserService public class UserService: IUserService
{ {
private readonly IUserRepository _userRepository;
private readonly IJwtHandler _jwtHandler;
private readonly IMapper _mapper;
public UserService(IUserRepository userRepository, IJwtHandler jwtHandler, IMapper mapper)
{
_userRepository = userRepository;
_jwtHandler = jwtHandler;
_mapper = mapper;
}
public async Task RegisterAsync(string email, string name, string surname, string login, string password)
{
if(await _userRepository.GetAsync(login) != null)
{
throw new Exception($"User with login: {login} already exists.");
}
var user = new User(email, name, surname, login, password);
await _userRepository.AddAsync(user);
}
public async Task<SignedUserDto> SignInAsync(string login, string password)
{
var user = await _userRepository.GetAsync(login);
if(user == null)
{
throw new Exception("User not found.");
}
if(user.Password != password)
{
throw new Exception("Incorrect password.");
}
var jwt = _jwtHandler.CreateToken(user.Id);
return new SignedUserDto()
{
User = _mapper.Map<UserDto>(user),
Jwt = _mapper.Map<JwtDto>(jwt)
};
}
} }
} }

View File

@ -6,6 +6,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AutoMapper" Version="10.1.1" /> <PackageReference Include="AutoMapper" Version="10.1.1" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.8.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.8.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serwer.Infrastructure.Settings
{
public class JwtSettings
{
public string Key { get; set; }
public string Issuer { get; set; }
public int ExpiryMinutes { get; set; }
}
}