This commit is contained in:
2018-10-05 01:51:23 +02:00
parent d2c1a9d5f9
commit 335c496133
6 changed files with 343 additions and 6 deletions

View File

@@ -7,6 +7,7 @@ namespace LaDOSE.Api.Context
public class LaDOSEDbContext : DbContext
{
public DbSet<Game> Game { get; set; }
public DbSet<ApplicationUser> ApplicationUser { get; set; }
public LaDOSEDbContext(DbContextOptions options) : base(options)
{

View File

@@ -4,18 +4,20 @@ using System.Linq;
using System.Threading.Tasks;
using LaDOSE.Api.Context;
using LaDOSE.Entity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LaDOSE.Api.Controllers
{
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ConfigController : ControllerBase
public class GameController : ControllerBase
{
private readonly LaDOSEDbContext _db;
public ConfigController(LaDOSEDbContext db)
public GameController(LaDOSEDbContext db)
{
_db = db;
}
@@ -27,12 +29,14 @@ namespace LaDOSE.Api.Controllers
return _db.Game.ToList();
}
// GET api/Config/5
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
public Game Get(int id)
{
return "value";
return _db.Game.FirstOrDefault(e=>e.Id==id);
}
}
}

View File

@@ -0,0 +1,106 @@
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;
using LaDOSE.Api.Services;
using LaDOSE.Entity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
namespace LaDOSE.Api.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
public class UsersController : ControllerBase
{
private IUserService _userService;
public UsersController(
IUserService userService
)
{
_userService = userService;
}
[AllowAnonymous]
[HttpGet("test")]
public String Test()
{
return "DEAD";
}
[HttpGet("test2")]
public String Test2()
{
return "DEAD";
}
[AllowAnonymous]
[HttpPost("authenticate")]
public IActionResult Authenticate([FromBody]ApplicationUser userDto)
{
var user = _userService.Authenticate(userDto.Username, userDto.Password);
if (user == null)
return BadRequest(new { message = "Username or password is incorrect" });
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes("this is my custom Secret key for authnetication");
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
// return basic user info (without password) and token to store client side
return Ok(new
{
Id = user.Id,
Username = user.Username,
FirstName = user.FirstName,
LastName = user.LastName,
Token = tokenString
});
}
[AllowAnonymous]
[HttpPost("register")]
public IActionResult Register([FromBody]ApplicationUser userDto)
{
// map dto to entity
try
{
// save
_userService.Create(userDto, userDto.Password);
return Ok();
}
catch (Exception ex)
{
// return error message if there was an exception
return BadRequest(new { message = ex.Message });
}
}
}
}

View File

@@ -0,0 +1,154 @@
using System;
using System.Collections.Generic;
using System.Linq;
using LaDOSE.Api.Context;
using LaDOSE.Entity;
namespace LaDOSE.Api.Services
{
public interface IUserService
{
ApplicationUser Authenticate(string username, string password);
IEnumerable<ApplicationUser> GetAll();
ApplicationUser GetById(int id);
ApplicationUser Create(ApplicationUser user, string password);
void Update(ApplicationUser user, string password = null);
void Delete(int id);
}
public class UserService : IUserService
{
private LaDOSEDbContext _context;
public UserService(LaDOSEDbContext context)
{
_context = context;
}
public ApplicationUser Authenticate(string username, string password)
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
return null;
var user = _context.ApplicationUser.SingleOrDefault(x => x.Username == username);
// check if username exists
if (user == null)
return null;
// check if password is correct
if (!VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt))
return null;
// authentication successful
return user;
}
public IEnumerable<ApplicationUser> GetAll()
{
return _context.ApplicationUser;
}
public ApplicationUser GetById(int id)
{
return _context.ApplicationUser.Find(id);
}
public ApplicationUser Create(ApplicationUser user, string password)
{
// validation
if (string.IsNullOrWhiteSpace(password))
throw new Exception("Password is required");
if (_context.ApplicationUser.Any(x => x.Username == user.Username))
throw new Exception("Username \"" + user.Username + "\" is already taken");
byte[] passwordHash, passwordSalt;
CreatePasswordHash(password, out passwordHash, out passwordSalt);
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
_context.ApplicationUser.Add(user);
_context.SaveChanges();
return user;
}
public void Update(ApplicationUser userParam, string password = null)
{
var user = _context.ApplicationUser.Find(userParam.Id);
if (user == null)
throw new Exception("User not found");
if (userParam.Username != user.Username)
{
// username has changed so check if the new username is already taken
if (_context.ApplicationUser.Any(x => x.Username == userParam.Username))
throw new Exception("Username " + userParam.Username + " is already taken");
}
// update user properties
user.FirstName = userParam.FirstName;
user.LastName = userParam.LastName;
user.Username = userParam.Username;
// update password if it was entered
if (!string.IsNullOrWhiteSpace(password))
{
byte[] passwordHash, passwordSalt;
CreatePasswordHash(password, out passwordHash, out passwordSalt);
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
}
_context.ApplicationUser.Update(user);
_context.SaveChanges();
}
public void Delete(int id)
{
var user = _context.ApplicationUser.Find(id);
if (user != null)
{
_context.ApplicationUser.Remove(user);
_context.SaveChanges();
}
}
// private helper methods
private static void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
{
if (password == null) throw new ArgumentNullException("password");
if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "password");
using (var hmac = new System.Security.Cryptography.HMACSHA512())
{
passwordSalt = hmac.Key;
passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
}
}
private static bool VerifyPasswordHash(string password, byte[] storedHash, byte[] storedSalt)
{
if (password == null) throw new ArgumentNullException("password");
if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "password");
if (storedHash.Length != 64) throw new ArgumentException("Invalid length of password hash (64 bytes expected).", "passwordHash");
if (storedSalt.Length != 128) throw new ArgumentException("Invalid length of password salt (128 bytes expected).", "passwordHash");
using (var hmac = new System.Security.Cryptography.HMACSHA512(storedSalt))
{
var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
for (int i = 0; i < computedHash.Length; i++)
{
if (computedHash[i] != storedHash[i]) return false;
}
}
return true;
}
}
}

View File

@@ -1,17 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LaDOSE.Api.Context;
using LaDOSE.Api.Services;
using LaDOSE.Entity;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Pomelo.EntityFrameworkCore.MySql;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
@@ -29,6 +35,7 @@ namespace LaDOSE.Api
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContextPool<LaDOSEDbContext>( // replace "YourDbContext" with the class name of your DbContext
options => options.UseMySql("Server=localhost;Database=ladose;User=root;Password=;", // replace with your Connection String
@@ -37,13 +44,53 @@ namespace LaDOSE.Api
mysqlOptions.ServerVersion(new Version(10, 1, 16), ServerType.MariaDb); // replace with your Server Version and Type
}
));
var key = Encoding.ASCII.GetBytes("this is my custom Secret key for authnetication");
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.Events = new JwtBearerEvents
{
OnTokenValidated = context =>
{
var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
var userId = int.Parse(context.Principal.Identity.Name);
var user = userService.GetById(userId);
if (user == null)
{
// return unauthorized if user no longer exists
context.Fail("Unauthorized");
}
return Task.CompletedTask;
}
};
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
// configure DI for application services
services.AddScoped<IUserService, UserService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
@@ -52,8 +99,14 @@ namespace LaDOSE.Api
{
app.UseHsts();
}
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc();
}
}