Add project files.
This commit is contained in:
		
							
								
								
									
										37
									
								
								TomatenMusic Api/Auth/Controllers/UsersController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								TomatenMusic Api/Auth/Controllers/UsersController.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| namespace WebApi.Controllers; | ||||
|  | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using TomatenMusic_Api.Auth.Helpers; | ||||
| using TomatenMusic_Api.Auth.Models; | ||||
| using TomatenMusic_Api.Auth.Services; | ||||
|  | ||||
| [ApiController] | ||||
| [Route("api/[controller]")] | ||||
| public class UsersController : ControllerBase | ||||
| { | ||||
|     private IUserService _userService; | ||||
|  | ||||
|     public UsersController(IUserService userService) | ||||
|     { | ||||
|         _userService = userService; | ||||
|     } | ||||
|  | ||||
|     [HttpPost("authenticate")] | ||||
|     public IActionResult Authenticate(AuthenticateRequest model) | ||||
|     { | ||||
|         var response = _userService.Authenticate(model); | ||||
|  | ||||
|         if (response == null) | ||||
|             return BadRequest(new { message = "Username or password is incorrect" }); | ||||
|  | ||||
|         return Ok(response); | ||||
|     } | ||||
|  | ||||
|     [Authorize] | ||||
|     [HttpGet] | ||||
|     public IActionResult GetAll() | ||||
|     { | ||||
|         var users = _userService.GetAll(); | ||||
|         return Ok(users); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										14
									
								
								TomatenMusic Api/Auth/Entities/User.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								TomatenMusic Api/Auth/Entities/User.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| namespace TomatenMusic_Api.Auth.Entities; | ||||
|  | ||||
| using System.Text.Json.Serialization; | ||||
|  | ||||
| public class User | ||||
| { | ||||
|     public int Id { get; set; } | ||||
|     public string FirstName { get; set; } | ||||
|     public string LastName { get; set; } | ||||
|     public string Username { get; set; } | ||||
|  | ||||
|     [JsonIgnore] | ||||
|     public string Password { get; set; } | ||||
| } | ||||
							
								
								
									
										6
									
								
								TomatenMusic Api/Auth/Helpers/AppSettings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								TomatenMusic Api/Auth/Helpers/AppSettings.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| namespace TomatenMusic_Api.Auth.Helpers; | ||||
|  | ||||
| public class AppSettings | ||||
| { | ||||
|     public string Secret { get; set; } | ||||
| } | ||||
							
								
								
									
										19
									
								
								TomatenMusic Api/Auth/Helpers/AuthorizeAttribute.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								TomatenMusic Api/Auth/Helpers/AuthorizeAttribute.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| namespace TomatenMusic_Api.Auth.Helpers; | ||||
|  | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.AspNetCore.Mvc.Filters; | ||||
| using TomatenMusic_Api.Auth.Entities; | ||||
|  | ||||
| [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] | ||||
| public class AuthorizeAttribute : Attribute, IAuthorizationFilter | ||||
| { | ||||
|     public void OnAuthorization(AuthorizationFilterContext context) | ||||
|     { | ||||
|         var user = (User)context.HttpContext.Items["User"]; | ||||
|         if (user == null) | ||||
|         { | ||||
|             // not logged in | ||||
|             context.Result = new JsonResult(new { message = "Unauthorized" }) { StatusCode = StatusCodes.Status401Unauthorized }; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										58
									
								
								TomatenMusic Api/Auth/Helpers/JwtMiddleware.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								TomatenMusic Api/Auth/Helpers/JwtMiddleware.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| namespace TomatenMusic_Api.Auth.Helpers; | ||||
|  | ||||
| using Microsoft.Extensions.Options; | ||||
| using Microsoft.IdentityModel.Tokens; | ||||
| using System.IdentityModel.Tokens.Jwt; | ||||
| using System.Text; | ||||
| using TomatenMusic_Api.Auth.Services; | ||||
|  | ||||
| public class JwtMiddleware | ||||
| { | ||||
|     private readonly RequestDelegate _next; | ||||
|     private readonly AppSettings _appSettings; | ||||
|  | ||||
|     public JwtMiddleware(RequestDelegate next, IOptions<AppSettings> appSettings) | ||||
|     { | ||||
|         _next = next; | ||||
|         _appSettings = appSettings.Value; | ||||
|     } | ||||
|  | ||||
|     public async Task Invoke(HttpContext context, IUserService userService) | ||||
|     { | ||||
|         var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last(); | ||||
|  | ||||
|         if (token != null) | ||||
|             attachUserToContext(context, userService, token); | ||||
|  | ||||
|         await _next(context); | ||||
|     } | ||||
|  | ||||
|     private void attachUserToContext(HttpContext context, IUserService userService, string token) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var tokenHandler = new JwtSecurityTokenHandler(); | ||||
|             var key = Encoding.ASCII.GetBytes(_appSettings.Secret); | ||||
|             tokenHandler.ValidateToken(token, new TokenValidationParameters | ||||
|             { | ||||
|                 ValidateIssuerSigningKey = true, | ||||
|                 IssuerSigningKey = new SymmetricSecurityKey(key), | ||||
|                 ValidateIssuer = false, | ||||
|                 ValidateAudience = false, | ||||
|                 // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later) | ||||
|                 ClockSkew = TimeSpan.Zero | ||||
|             }, out SecurityToken validatedToken); | ||||
|  | ||||
|             var jwtToken = (JwtSecurityToken)validatedToken; | ||||
|             var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value); | ||||
|  | ||||
|             // attach user to context on successful jwt validation | ||||
|             context.Items["User"] = userService.GetById(userId); | ||||
|         } | ||||
|         catch | ||||
|         { | ||||
|             // do nothing if jwt validation fails | ||||
|             // user is not attached to context so request won't have access to secure routes | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								TomatenMusic Api/Auth/Models/AuthenticateRequest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								TomatenMusic Api/Auth/Models/AuthenticateRequest.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| namespace TomatenMusic_Api.Auth.Models; | ||||
|  | ||||
| using System.ComponentModel.DataAnnotations; | ||||
|  | ||||
| public class AuthenticateRequest | ||||
| { | ||||
|     [Required] | ||||
|     public string Username { get; set; } | ||||
|  | ||||
|     [Required] | ||||
|     public string Password { get; set; } | ||||
| } | ||||
							
								
								
									
										22
									
								
								TomatenMusic Api/Auth/Models/AuthenticateResponse.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								TomatenMusic Api/Auth/Models/AuthenticateResponse.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| namespace TomatenMusic_Api.Auth.Models; | ||||
|  | ||||
| using TomatenMusic_Api.Auth.Entities; | ||||
|  | ||||
| public class AuthenticateResponse | ||||
| { | ||||
|     public int Id { get; set; } | ||||
|     public string FirstName { get; set; } | ||||
|     public string LastName { get; set; } | ||||
|     public string Username { get; set; } | ||||
|     public string Token { get; set; } | ||||
|  | ||||
|  | ||||
|     public AuthenticateResponse(User user, string token) | ||||
|     { | ||||
|         Id = user.Id; | ||||
|         FirstName = user.FirstName; | ||||
|         LastName = user.LastName; | ||||
|         Username = user.Username; | ||||
|         Token = token; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										75
									
								
								TomatenMusic Api/Auth/Services/UserService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								TomatenMusic Api/Auth/Services/UserService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| namespace TomatenMusic_Api.Auth.Services; | ||||
|  | ||||
| using Microsoft.Extensions.Options; | ||||
| using Microsoft.IdentityModel.Tokens; | ||||
| using System.IdentityModel.Tokens.Jwt; | ||||
| using System.Security.Claims; | ||||
| using System.Text; | ||||
| using TomatenMusic_Api.Auth.Entities; | ||||
| using TomatenMusic_Api.Auth.Helpers; | ||||
| using TomatenMusic_Api.Auth.Models; | ||||
|  | ||||
| public interface IUserService | ||||
| { | ||||
|     AuthenticateResponse Authenticate(AuthenticateRequest model); | ||||
|     IEnumerable<User> GetAll(); | ||||
|     User GetById(int id); | ||||
| } | ||||
|  | ||||
| public class UserService : IUserService | ||||
| { | ||||
|     // users hardcoded for simplicity, store in a db with hashed passwords in production applications | ||||
|     private List<User> _users = new List<User> | ||||
|     { | ||||
|         new User { Id = 1, FirstName = "Jannick", LastName = "Voss", Username = "Glowman", Password = "RX5GXstLLBvdt#_N" }, | ||||
|         new User { Id = 2, FirstName = "Tim", LastName= "M<>ller", Password= "SGWaldsolms9", Username = "Tueem"} | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     private readonly AppSettings _appSettings; | ||||
|  | ||||
|     public UserService(IOptions<AppSettings> appSettings) | ||||
|     { | ||||
|         _appSettings = appSettings.Value; | ||||
|     } | ||||
|  | ||||
|     public AuthenticateResponse Authenticate(AuthenticateRequest model) | ||||
|     { | ||||
|         var user = _users.SingleOrDefault(x => x.Username == model.Username && x.Password == model.Password); | ||||
|  | ||||
|         // return null if user not found | ||||
|         if (user == null) return null; | ||||
|  | ||||
|         // authentication successful so generate jwt token | ||||
|         var token = generateJwtToken(user); | ||||
|  | ||||
|         return new AuthenticateResponse(user, token); | ||||
|     } | ||||
|  | ||||
|     public IEnumerable<User> GetAll() | ||||
|     { | ||||
|         return _users; | ||||
|     } | ||||
|  | ||||
|     public User GetById(int id) | ||||
|     { | ||||
|         return _users.FirstOrDefault(x => x.Id == id); | ||||
|     } | ||||
|  | ||||
|     // helper methods | ||||
|  | ||||
|     private string generateJwtToken(User user) | ||||
|     { | ||||
|         // generate token that is valid for 7 days | ||||
|         var tokenHandler = new JwtSecurityTokenHandler(); | ||||
|         var key = Encoding.ASCII.GetBytes(_appSettings.Secret); | ||||
|         var tokenDescriptor = new SecurityTokenDescriptor | ||||
|         { | ||||
|             Subject = new ClaimsIdentity(new[] { new Claim("id", user.Id.ToString()) }), | ||||
|             Expires = DateTime.UtcNow.AddDays(1), | ||||
|             SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) | ||||
|         }; | ||||
|         var token = tokenHandler.CreateToken(tokenDescriptor); | ||||
|         return tokenHandler.WriteToken(token); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Tim Müller
					Tim Müller