add bearer authentication!
This commit is contained in:
parent
1d5570c578
commit
0ead15ce5a
20
.vscode/launch.json
vendored
20
.vscode/launch.json
vendored
@ -4,6 +4,26 @@
|
|||||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": ".NET Core Launch (api)",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
"program": "${workspaceFolder}/Apps/Api/bin/Debug/net5.0/Api.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}/Apps/Api",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"serverReadyAction": {
|
||||||
|
"action": "openExternally",
|
||||||
|
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"sourceFileMap": {
|
||||||
|
"/Views": "${workspaceFolder}/Views"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": ".NET Core Launch (web)",
|
"name": ".NET Core Launch (web)",
|
||||||
"type": "coreclr",
|
"type": "coreclr",
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.1" />
|
||||||
<PackageReference Include="NSwag.AspNetCore" Version="13.9.4" />
|
<PackageReference Include="NSwag.AspNetCore" Version="13.9.4" />
|
||||||
<PackageReference Include="NSwag.MSBuild" Version="13.9.4">
|
<PackageReference Include="NSwag.MSBuild" Version="13.9.4">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|||||||
70
Apps/Api/Controllers/AccountsController.cs
Normal file
70
Apps/Api/Controllers/AccountsController.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
using System;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Api.Models;
|
||||||
|
using HN.Infrastructure.Identity;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace Api.Controllers
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public sealed class AccountsController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly UserManager<User> _usersManager;
|
||||||
|
private readonly SignInManager<User> _signinManager;
|
||||||
|
private readonly TokenValidationParameters _tokenParameters;
|
||||||
|
|
||||||
|
public AccountsController(UserManager<User> usersManager, SignInManager<User> signinManager, TokenValidationParameters tokenParameters)
|
||||||
|
{
|
||||||
|
_usersManager = usersManager;
|
||||||
|
_signinManager = signinManager;
|
||||||
|
_tokenParameters = tokenParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
public IActionResult GetUsers()
|
||||||
|
{
|
||||||
|
return Ok(_usersManager.Users.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("login")]
|
||||||
|
public async Task<IActionResult> Login(LoginViewModel command)
|
||||||
|
{
|
||||||
|
var user = await _usersManager.FindByNameAsync(command.Username);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await _signinManager.CheckPasswordSignInAsync(user, command.Password, false);
|
||||||
|
|
||||||
|
if (!result.Succeeded)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenDescriptor = new SecurityTokenDescriptor
|
||||||
|
{
|
||||||
|
Subject = new ClaimsIdentity(new Claim[]
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
||||||
|
new Claim(ClaimTypes.Name, command.Username),
|
||||||
|
}),
|
||||||
|
|
||||||
|
Expires = DateTime.UtcNow.AddDays(7),
|
||||||
|
Issuer = _tokenParameters.ValidIssuer,
|
||||||
|
Audience = _tokenParameters.ValidAudience,
|
||||||
|
SigningCredentials = new SigningCredentials(_tokenParameters.IssuerSigningKey, SecurityAlgorithms.HmacSha256Signature)
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(new JwtSecurityTokenHandler().CreateEncodedJwt(tokenDescriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -102,7 +102,7 @@ namespace Api.Controllers
|
|||||||
{
|
{
|
||||||
var result = await _bus.Send(command);
|
var result = await _bus.Send(command);
|
||||||
|
|
||||||
return CreatedAtAction(nameof(GetLinkById), new { id = result });
|
return CreatedAtAction(nameof(GetLinkById), new { id = result }, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
13
Apps/Api/Models/LoginViewModel.cs
Normal file
13
Apps/Api/Models/LoginViewModel.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Api.Models
|
||||||
|
{
|
||||||
|
public sealed class LoginViewModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,24 +1,19 @@
|
|||||||
using System;
|
using System.Text;
|
||||||
using HN.Application;
|
|
||||||
using HN.Infrastructure;
|
using HN.Infrastructure;
|
||||||
|
using HN.Infrastructure.Identity;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
namespace Api
|
namespace Api
|
||||||
{
|
{
|
||||||
public class MockExecutingContext : IExecutingUserProvider
|
|
||||||
{
|
|
||||||
public Guid GetCurrentUserId()
|
|
||||||
{
|
|
||||||
return Guid.NewGuid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
public Startup(IConfiguration configuration)
|
public Startup(IConfiguration configuration)
|
||||||
@ -32,7 +27,7 @@ namespace Api
|
|||||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddHN(Configuration).ResolveConnectedUserWith<MockExecutingContext>();
|
services.AddHN(Configuration).ResolveConnectedUserWith<HttpExecutingUserProvider>();
|
||||||
services.AddHttpContextAccessor();
|
services.AddHttpContextAccessor();
|
||||||
|
|
||||||
// Permet d'avoir des routes en lowercase
|
// Permet d'avoir des routes en lowercase
|
||||||
@ -42,6 +37,31 @@ namespace Api
|
|||||||
options.LowercaseQueryStrings = true;
|
options.LowercaseQueryStrings = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Ajout de l'authentification
|
||||||
|
var tokenParams = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
ValidIssuer = Configuration["JwtIssuer"],
|
||||||
|
ValidAudience = Configuration["JwtAudience"],
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSecurityKey"]))
|
||||||
|
};
|
||||||
|
|
||||||
|
services.AddSingleton(tokenParams);
|
||||||
|
|
||||||
|
services.AddIdentityCore<User>()
|
||||||
|
.AddRoles<Role>()
|
||||||
|
.AddEntityFrameworkStores<HNDbContext>()
|
||||||
|
.AddSignInManager();
|
||||||
|
|
||||||
|
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
|
.AddJwtBearer(o =>
|
||||||
|
{
|
||||||
|
o.TokenValidationParameters = tokenParams;
|
||||||
|
});
|
||||||
|
|
||||||
services.AddControllers();
|
services.AddControllers();
|
||||||
services.AddSwaggerDocument(d =>
|
services.AddSwaggerDocument(d =>
|
||||||
{
|
{
|
||||||
@ -66,6 +86,9 @@ namespace Api
|
|||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
endpoints.MapControllers();
|
endpoints.MapControllers();
|
||||||
|
|||||||
@ -9,5 +9,8 @@
|
|||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"Default": "Data Source=../Website/hn.db"
|
"Default": "Data Source=../Website/hn.db"
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*",
|
||||||
|
"JwtIssuer": "http://localhost",
|
||||||
|
"JwtAudience": "http://localhost",
|
||||||
|
"JwtSecurityKey": "CTtgxbcSFbpJmdmLDnr3Y8h5RWseN7t5"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,60 @@
|
|||||||
"version": "1.0.0"
|
"version": "1.0.0"
|
||||||
},
|
},
|
||||||
"paths": {
|
"paths": {
|
||||||
|
"/api/accounts": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"Accounts"
|
||||||
|
],
|
||||||
|
"operationId": "Accounts_GetUsers",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/octet-stream": {
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "binary"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/accounts/login": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Accounts"
|
||||||
|
],
|
||||||
|
"operationId": "Accounts_Login",
|
||||||
|
"requestBody": {
|
||||||
|
"x-name": "command",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/LoginViewModel"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"x-position": 1
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/octet-stream": {
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "binary"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/links": {
|
"/api/links": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
@ -232,6 +286,24 @@
|
|||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
"schemas": {
|
"schemas": {
|
||||||
|
"LoginViewModel": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"username",
|
||||||
|
"password"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"username": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"LinkDto": {
|
"LinkDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
|
|||||||
@ -65,15 +65,7 @@ namespace Website.Controllers
|
|||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = await _userManager.FindByNameAsync(command.Username);
|
var result = await _signInManager.PasswordSignInAsync(command.Username, command.Password, true, false);
|
||||||
|
|
||||||
if (user == null)
|
|
||||||
{
|
|
||||||
ModelState.AddModelError(nameof(LoginViewModel.Username), "Could not verify user identity");
|
|
||||||
return View();
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = await _signInManager.PasswordSignInAsync(user, command.Password, true, false);
|
|
||||||
|
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user