This repository has been archived by the owner on Jun 5, 2021. It is now read-only.
-
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
120d63b
commit ceac5c9
Showing
6 changed files
with
223 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,7 @@ | ||
namespace SchoolManagament.API.Security | ||
{ | ||
public class AppSettings | ||
{ | ||
public string Secret { get; set; } | ||
} | ||
} |
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 System.Collections.Generic; | ||
using System.ComponentModel.DataAnnotations; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
|
||
namespace SchoolManagement.API.Security | ||
{ | ||
public class AuthenticationRequest | ||
{ | ||
[Required(ErrorMessage = "User Name is required")] | ||
public string Username { get; set; } | ||
|
||
[Required(ErrorMessage = "Password is required")] | ||
public string Password { get; set; } | ||
} | ||
} |
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,27 @@ | ||
using SchoolManagement.API.Models; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
|
||
namespace SchoolManagement.API.Security | ||
{ | ||
public class AuthenticationResponse | ||
{ | ||
public int RoleId { get; set; } | ||
public string FirstName { get; set; } | ||
public string LastName { get; set; } | ||
public string Username { get; set; } | ||
public string Token { get; set; } | ||
|
||
|
||
public AuthenticationResponse(User user, string token) | ||
{ | ||
RoleId = user.RoleId; | ||
FirstName = user.Name; | ||
LastName = user.Surname; | ||
Username = user.Username; | ||
Token = token; | ||
} | ||
} | ||
} |
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,34 @@ | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.AspNetCore.Mvc.Filters; | ||
using System; | ||
using SchoolManagement.API.Models; | ||
namespace SchoolManagament.API.Security | ||
{ | ||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] | ||
public class AuthorizeAttribute : Attribute, IAuthorizationFilter | ||
{ | ||
private readonly int _roleID; | ||
public AuthorizeAttribute() | ||
{ | ||
_roleID = 0; | ||
} | ||
public AuthorizeAttribute(int roleID) | ||
{ | ||
_roleID = roleID; | ||
} | ||
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 }; | ||
} | ||
else if(user.RoleId != _roleID) | ||
{ | ||
context.Result = new JsonResult(new { message = "Forbidden" }) { StatusCode = StatusCodes.Status403Forbidden }; | ||
} | ||
} | ||
} | ||
} |
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,61 @@ | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.Extensions.Options; | ||
using Microsoft.IdentityModel.Tokens; | ||
using System; | ||
using System.IdentityModel.Tokens.Jwt; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace SchoolManagament.API.Security | ||
{ | ||
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, | ||
|
||
ClockSkew = TimeSpan.Zero | ||
}, out SecurityToken validatedToken); | ||
|
||
var jwtToken = (JwtSecurityToken)validatedToken; | ||
var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value); | ||
|
||
|
||
context.Items["User"] = userService.GetById(userId); | ||
} | ||
catch | ||
{ | ||
|
||
} | ||
} | ||
} | ||
} |
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,77 @@ | ||
using Microsoft.Extensions.Options; | ||
using Microsoft.IdentityModel.Tokens; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IdentityModel.Tokens.Jwt; | ||
using System.Linq; | ||
using System.Security.Claims; | ||
using System.Text; | ||
using SchoolManagement.API.Models; | ||
using SchoolManagement.API.Security; | ||
using SchoolManagement.API.Data; | ||
|
||
namespace SchoolManagament.API.Security | ||
{ | ||
public interface IUserService | ||
{ | ||
AuthenticationResponse Authenticate(AuthenticationRequest 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 readonly IRepo<User> _users; | ||
|
||
private readonly AppSettings _appSettings; | ||
|
||
public UserService(IOptions<AppSettings> appSettings,IRepo<User> users) | ||
{ | ||
_appSettings = appSettings.Value; | ||
_users = users; | ||
} | ||
|
||
public AuthenticationResponse Authenticate(AuthenticationRequest model) | ||
{ | ||
var users = _users.GetByPredicate(x => x.Username == model.Username && x.Password == model.Password); | ||
|
||
//var user = users[0]; | ||
// return null if user not found | ||
if (users.Count < 1) return null; | ||
|
||
// authentication successful so generate jwt token | ||
var token = generateJwtToken(users[0]); | ||
|
||
return new AuthenticationResponse(users[0], token); | ||
} | ||
|
||
public IEnumerable<User> GetAll() | ||
{ | ||
List<User> users = _users.GetAll().Result; | ||
return users; | ||
} | ||
|
||
public User GetById(int id) | ||
{ | ||
return _users.GetById(id).Result; | ||
} | ||
|
||
// 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()), new Claim(ClaimTypes.Role, "ADMIN") }), | ||
Expires = DateTime.UtcNow.AddDays(1), | ||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) | ||
}; | ||
var token = tokenHandler.CreateToken(tokenDescriptor); | ||
return tokenHandler.WriteToken(token); | ||
} | ||
} | ||
} |