forked from EduardoPires/EquinoxProject
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7a4d681
commit 52919d9
Showing
16 changed files
with
747 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace Equinox.Services.Api.Configurations | ||
{ | ||
public class AppSettings | ||
{ | ||
public string Secret { get; set; } | ||
public int Expiration { get; set; } | ||
public string Issuer { get; set; } | ||
public string ValidAt { get; set; } | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/Equinox.Services.Api/Configurations/AutoMapperSetup.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System; | ||
using AutoMapper; | ||
using Equinox.Application.AutoMapper; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Equinox.Services.Api.Configurations | ||
{ | ||
public static class AutoMapperSetup | ||
{ | ||
public static void AddAutoMapperSetup(this IServiceCollection services) | ||
{ | ||
if (services == null) throw new ArgumentNullException(nameof(services)); | ||
|
||
services.AddAutoMapper(typeof(DomainToViewModelMappingProfile), typeof(ViewModelToDomainMappingProfile)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System; | ||
using Equinox.Infra.CrossCutting.Identity.Models; | ||
using Equinox.Infra.Data.Context; | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Equinox.Services.Api.Configurations | ||
{ | ||
public static class DatabaseSetup | ||
{ | ||
public static void AddDatabaseSetup(this IServiceCollection services, IConfiguration configuration) | ||
{ | ||
if (services == null) throw new ArgumentNullException(nameof(services)); | ||
|
||
services.AddDbContext<ApplicationDbContext>(options => | ||
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"))); | ||
|
||
services.AddDbContext<EquinoxContext>(options => | ||
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"))); | ||
|
||
services.AddDbContext<EventStoreSqlContext>(options => | ||
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"))); | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/Equinox.Services.Api/Configurations/DependencyInjectionSetup.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using System; | ||
using Equinox.Infra.CrossCutting.IoC; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Equinox.Services.Api.Configurations | ||
{ | ||
public static class DependencyInjectionSetup | ||
{ | ||
public static void AddDependencyInjectionSetup(this IServiceCollection services) | ||
{ | ||
if (services == null) throw new ArgumentNullException(nameof(services)); | ||
|
||
NativeInjectorBootStrapper.RegisterServices(services); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
using System; | ||
using System.Text; | ||
using Equinox.Infra.CrossCutting.Identity.Authorization; | ||
using Equinox.Infra.CrossCutting.Identity.Models; | ||
using Microsoft.AspNetCore.Authentication.JwtBearer; | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Identity; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.IdentityModel.Tokens; | ||
|
||
namespace Equinox.Services.Api.Configurations | ||
{ | ||
public static class IdentitySetup | ||
{ | ||
public static void AddIdentitySetup(this IServiceCollection services, IConfiguration configuration) | ||
{ | ||
if (services == null) throw new ArgumentNullException(nameof(services)); | ||
|
||
services.AddDefaultIdentity<IdentityUser>() | ||
.AddRoles<IdentityRole>() | ||
.AddEntityFrameworkStores<ApplicationDbContext>() | ||
.AddDefaultTokenProviders(); | ||
|
||
// JWT Setup | ||
|
||
var appSettingsSection = configuration.GetSection("AppSettings"); | ||
services.Configure<AppSettings>(appSettingsSection); | ||
|
||
var appSettings = appSettingsSection.Get<AppSettings>(); | ||
var key = Encoding.ASCII.GetBytes(appSettings.Secret); | ||
|
||
services.AddAuthentication(x => | ||
{ | ||
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; | ||
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; | ||
}).AddJwtBearer(x => | ||
{ | ||
x.RequireHttpsMetadata = true; | ||
x.SaveToken = true; | ||
x.TokenValidationParameters = new TokenValidationParameters | ||
{ | ||
ValidateIssuerSigningKey = true, | ||
IssuerSigningKey = new SymmetricSecurityKey(key), | ||
ValidateIssuer = true, | ||
ValidateAudience = true, | ||
ValidAudience = appSettings.ValidAt, | ||
ValidIssuer = appSettings.Issuer | ||
}; | ||
}); | ||
|
||
services.AddAuthorization(options => | ||
{ | ||
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme); | ||
defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser(); | ||
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build(); | ||
}); | ||
} | ||
|
||
public static void AddAuthSetup(this IServiceCollection services, IConfiguration configuration) | ||
{ | ||
if (services == null) throw new ArgumentNullException(nameof(services)); | ||
|
||
services.AddAuthorization(options => | ||
{ | ||
options.AddPolicy("CanWriteCustomerData", policy => policy.Requirements.Add(new ClaimRequirement("Customers", "Write"))); | ||
options.AddPolicy("CanRemoveCustomerData", policy => policy.Requirements.Add(new ClaimRequirement("Customers", "Remove"))); | ||
}); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.OpenApi.Models; | ||
|
||
namespace Equinox.Services.Api.Configurations | ||
{ | ||
public static class SwaggerSetup | ||
{ | ||
public static void AddSwaggerSetup(this IServiceCollection services) | ||
{ | ||
if (services == null) throw new ArgumentNullException(nameof(services)); | ||
|
||
services.AddSwaggerGen(s => | ||
{ | ||
s.SwaggerDoc("v1", new OpenApiInfo | ||
{ | ||
Version = "v1", | ||
Title = "Equinox Project", | ||
Description = "Equinox API Swagger surface", | ||
Contact = new OpenApiContact { Name = "Eduardo Pires", Email = "[email protected]", Url = new Uri("http://www.eduardopires.net.br") }, | ||
License = new OpenApiLicense() { Name = "MIT", Url = new Uri("https://github.com/EduardoPires/EquinoxProject/blob/master/LICENSE") } | ||
}); | ||
|
||
s.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme | ||
{ | ||
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", | ||
Name = "Authorization", | ||
In = ParameterLocation.Header, | ||
Type = SecuritySchemeType.ApiKey, | ||
Scheme = "Bearer" | ||
}); | ||
|
||
s.AddSecurityRequirement(new OpenApiSecurityRequirement | ||
{ | ||
{ | ||
new OpenApiSecurityScheme | ||
{ | ||
Reference = new OpenApiReference | ||
{ | ||
Type = ReferenceType.SecurityScheme, | ||
Id = "Bearer" | ||
}, | ||
Scheme = "oauth2", | ||
Name = "Bearer", | ||
In = ParameterLocation.Header, | ||
|
||
}, | ||
new List<string>() | ||
} | ||
}); | ||
|
||
}); | ||
} | ||
|
||
public static void UseSwaggerSetup(this IApplicationBuilder app) | ||
{ | ||
if (app == null) throw new ArgumentNullException(nameof(app)); | ||
|
||
app.UseSwagger(); | ||
app.UseSwaggerUI(c => | ||
{ | ||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Equinox Project"); | ||
}); | ||
} | ||
} | ||
} |
120 changes: 120 additions & 0 deletions
120
src/Equinox.Services.Api/Controllers/AccountController.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
using System; | ||
using System.IdentityModel.Tokens.Jwt; | ||
using System.Security.Claims; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Equinox.Domain.Core.Bus; | ||
using Equinox.Domain.Core.Notifications; | ||
using Equinox.Infra.CrossCutting.Identity.Models; | ||
using Equinox.Services.Api.Configurations; | ||
using MediatR; | ||
using Microsoft.AspNetCore.Identity; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.Extensions.Options; | ||
using Microsoft.IdentityModel.Tokens; | ||
|
||
namespace Equinox.Services.Api.Controllers | ||
{ | ||
[Route("api/[controller]")] | ||
[ApiController] | ||
public class AccountController : ApiController | ||
{ | ||
private readonly SignInManager<IdentityUser> _signInManager; | ||
private readonly UserManager<IdentityUser> _userManager; | ||
private readonly AppSettings _appSettings; | ||
|
||
public AccountController( | ||
SignInManager<IdentityUser> signInManager, | ||
UserManager<IdentityUser> userManager, | ||
IOptions<AppSettings> appSettings, | ||
INotificationHandler<DomainNotification> notifications, | ||
IMediatorHandler mediator) : base(notifications, mediator) | ||
{ | ||
_userManager = userManager; | ||
_signInManager = signInManager; | ||
_appSettings = appSettings.Value; | ||
} | ||
|
||
[HttpPost] | ||
[Route("register")] | ||
public async Task<IActionResult> Register(UserRegistration userRegistration) | ||
{ | ||
if (!ModelState.IsValid) | ||
{ | ||
NotifyModelStateErrors(); | ||
return Response(userRegistration); | ||
} | ||
|
||
var user = new IdentityUser | ||
{ | ||
UserName = userRegistration.Email, | ||
Email = userRegistration.Email, | ||
EmailConfirmed = true | ||
}; | ||
|
||
var result = await _userManager.CreateAsync(user, userRegistration.Password); | ||
|
||
if (!result.Succeeded) | ||
{ | ||
foreach (var error in result.Errors) | ||
{ | ||
NotifyError(error.Code, error.Description); | ||
} | ||
|
||
return Response(userRegistration); | ||
} | ||
|
||
await _signInManager.SignInAsync(user, false); | ||
var token = await GenerateJwt(userRegistration.Email); | ||
|
||
return Response(token); | ||
} | ||
|
||
[HttpPost] | ||
[Route("login")] | ||
public async Task<IActionResult> Login(UserLogin userLogin) | ||
{ | ||
if (!ModelState.IsValid) | ||
{ | ||
NotifyModelStateErrors(); | ||
return Response(userLogin); | ||
} | ||
|
||
var result = await _signInManager.PasswordSignInAsync(userLogin.Email, userLogin.Password, false, true); | ||
|
||
if (result.Succeeded) | ||
{ | ||
var token = await GenerateJwt(userLogin.Email); | ||
return Response(token); | ||
} | ||
|
||
NotifyError("Login", result.ToString()); | ||
return Response(userLogin); | ||
} | ||
|
||
private async Task<string> GenerateJwt(string email) | ||
{ | ||
var user = await _userManager.FindByEmailAsync(email); | ||
var claims = await _userManager.GetClaimsAsync(user); | ||
|
||
claims.Add(new Claim(JwtRegisteredClaimNames.Sub, user.Id)); | ||
claims.Add(new Claim(JwtRegisteredClaimNames.Email, user.Email)); | ||
|
||
var identityClaims = new ClaimsIdentity(); | ||
identityClaims.AddClaims(claims); | ||
|
||
var tokenHandler = new JwtSecurityTokenHandler(); | ||
var key = Encoding.ASCII.GetBytes(_appSettings.Secret); | ||
var tokenDescriptor = new SecurityTokenDescriptor | ||
{ | ||
Subject = identityClaims, | ||
Issuer = _appSettings.Issuer, | ||
Audience = _appSettings.ValidAt, | ||
Expires = DateTime.UtcNow.AddHours(_appSettings.Expiration), | ||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) | ||
}; | ||
|
||
return tokenHandler.WriteToken(tokenHandler.CreateToken(tokenDescriptor)); | ||
} | ||
} | ||
} |
Oops, something went wrong.