South Africa’s biggest forum. Discuss, discover, and connect with thousands of members.
Whatever you say...blahblah is what I see^^^^ Dunning–Kruger
If you would like to progress past junior developer you could do worse than reading all my posts in this sub-forumWhatever you say...blahblah is what I see
If you would like to progress past junior developer you could do worse than reading all my posts in this sub-forum![]()
{
"sub": "[email protected]",
"jti": "94a9f405-c57e-4271-8df3-2a94a56a92d2",
"email": "[email protected]",
"id": "1",
"role": "Admin",
"nbf": 1616836176,
"exp": 1616843376,
"iat": 1616836176
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
#region "JWT Token For Authentication Login"
app.UseCookiePolicy();
app.UseSession();
app.Use(async (context, next) =>
{
var JWToken = context.Session.GetString("JWToken");
if (!string.IsNullOrEmpty(JWToken))
{
context.Request.Headers.Add("Authorization", "Bearer " + JWToken);
}
await next();
});
app.UseAuthentication();
app.UseAuthorization();
Use Identity don’t roll your own authentication which is essentially what that code is doing._kabal_ has raked my code over the coals a few times in the past. It has only pushed me harder to be better tbh.
I have solved that issue with the Async etc. The problem was my login page. Not sure what but I deleted it and recreated it using the standard bootstrap page and went with another time tested example of loging pages from
![]()
User Registration And Login Form With E-Mail Notification In MVC
In this article, you will see how to create a user registration form and a login form.www.c-sharpcorner.com
I am just working now on reading the role and various other user information from the token itself HOWEVER I'm not convinced I need to do that at all. Just figuring out how to get the token information into the Session.
This is from the decoded Token. Getting there slowly.
![]()
JWT.IO
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.jwt.io
Code:{ "sub": "[email protected]", "jti": "94a9f405-c57e-4271-8df3-2a94a56a92d2", "email": "[email protected]", "id": "1", "role": "Admin", "nbf": 1616836176, "exp": 1616843376, "iat": 1616836176 }
I have noticed this
Code:app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); #region "JWT Token For Authentication Login" app.UseCookiePolicy(); app.UseSession(); app.Use(async (context, next) => { var JWToken = context.Session.GetString("JWToken"); if (!string.IsNullOrEmpty(JWToken)) { context.Request.Headers.Add("Authorization", "Bearer " + JWToken); } await next(); }); app.UseAuthentication(); app.UseAuthorization();
And This in the authentication controller. Just piecing it together.
HttpContext.Session.SetString("JWToken", token);
Use Identity don’t roll your own authentication which is essentially what that code is doing.
if you don’t need JWT, use cookies. Less management.
That’s fair, each aspect is broken up though.Not every company wants or will allow those Identity tables on their database. I have gone with own solution with my own tables. It's also a good way to learn about all this stuff. I hash and salt the passords myself, verify using BCrypt.Net. Its close now just have to wrap up the token handling on the front end.
private static void ConfigureAuth(IServiceCollection services, string secret)
{
var key = Encoding.ASCII.GetBytes(secret);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
services.AddScoped<UserService>();
}
public class UserService
{
private readonly List<User> _users = new List<User>
{
new User {Id = 1, FirstName = "Admin", LastName = "User", Username = "admin", Password = "123456"}
};
private readonly AppSettings _appSettings;
public UserService(IOptions<AppSettings> appSettings)
{
_appSettings = appSettings.Value;
}
public User Authenticate(string username, string password)
{
var user = _users.SingleOrDefault(x => x.Username == username && x.Password == password);
if (user is null)
{
return null;
}
// authentication successful so generate jwt token
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
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);
user.Token = tokenHandler.WriteToken(token);
return user.WithoutPassword();
}
public IEnumerable<User> GetAll()
{
return _users.WithoutPasswords();
}
}
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Token { get; set; }
}
public static class UserExtensions
{
public static IEnumerable<User> WithoutPasswords(this IEnumerable<User> users) {
return users.Select(x => x.WithoutPassword());
}
public static User WithoutPassword(this User user) {
user.Password = null;
return user;
}
}
[Authorize]
[ApiController]
[Route("/api/users")]
public class UsersController : ControllerBase
{
private readonly UserService _userService;
public UsersController(UserService userService)
{
_userService = userService;
}
[AllowAnonymous]
[HttpPost("authenticate")]
public IActionResult Authenticate([FromBody]User userParam)
{
var user = _userService.Authenticate(userParam.Username, userParam.Password);
if (user is null)
{
return BadRequest(new { message = "Username or password is incorrect" }); // could argue that this should return 401, but IMO that is ambiguous as it could also read "you are not authorised to call this endpoint;
}
return Ok(user);
}
[HttpGet]
public IActionResult GetAll()
{
var users = _userService.GetAll();
return Ok(users);
}
[HttpGet("me")]
public IActionResult Me()
{
var user = _userService.GetAll().FirstOrDefault();
return Ok(user);
}
}
public class AuthenticationResult
{
public string Token { get; set; }
public bool Succes { get; set; }
public IEnumerable<string> Errors { get; set; }
}
public async Task<AuthenticationResult> LoginAsync(string email, string password)
{
var user = await _userService.FindByEmailAsync(email);
if (user == null)
{
return new AuthenticationResult
{
Errors = new[] { "User does not exist." }
};
}
var userHasValidPassword = await _userService.LoginValidate(email, password);
if (!userHasValidPassword)
{
return new AuthenticationResult
{
Errors = new[] { "Username/password combination is wrong!" }
};
}
return await GenerateAuthenticationResultForUser(user);
}
private async Task<AuthenticationResult> GenerateAuthenticationResultForUser(Employee user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtSettings.Secret);
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, user.EmailAddress),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Email, user.EmailAddress),
new Claim("id", user.Id.ToString())
};
//Check for existing user
string empRole = await _userService.GetRole(user.Id);
//If current user logging in with a role
if (!string.IsNullOrEmpty(empRole))
{
claims.Add(new Claim(ClaimTypes.Role, empRole));
}
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.UtcNow.AddHours(2),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return new AuthenticationResult
{
Succes = true,
Token = tokenHandler.WriteToken(token)
};
}
public async Task<ActionResult> Validate(Employee employee)
{
if (await _serviceClient.LoginUserAsync(_apiUrl + "Identity/Login", employee.EmailAddress, employee.Password))
{
HttpContext.Session.SetString("email", employee.EmailAddress);
HttpContext.Session.SetInt32("id", employee.Id);
HttpContext.Session.SetInt32("role_id", (int)employee.RoleId);
HttpContext.Session.SetString("name", employee.FullName);
HttpContext.Session.SetString("user_role", employee.EmployeeRole.RoleDescription);
return Json(new { status = true, message = "Login Successfull!" });
}
else
{
return Json(new { status = true, message = "Invalid Login!" });
}
}
public async Task<bool> LoginUserAsync(string url, string emailAddress, string password)
{
try
{
TokenRequest Token;
HttpClient client = new HttpClient();
var values = new Dictionary<string, string>
{
{ "email", emailAddress },
{ "password", password}
};
var content = new StringContent(JsonConvert.SerializeObject(values), Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
var responseString = await response.Content.ReadAsStringAsync();
Token = JsonConvert.DeserializeObject<TokenRequest>(responseString);
}
catch(Exception ex)
{
throw ex;
}
return true;
}
{
"sub": "[email protected]",
"jti": "94a9f405-c57e-4271-8df3-2a94a56a92d2",
"email": "[email protected]",
"id": "1",
"role": "Admin",
"nbf": 1616836176,
"exp": 1616843376,
"iat": 1616836176
}
What is the service you’re getting the token from?
Sorry I meant the API url you’re calling to get the token, what service is that?That's from these namespaces from Nuget
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
var tokenHandler = new JwtSecurityTokenHandler();
Just call it here like so
var token = tokenHandler.CreateToken(tokenDescriptor);
Token = tokenHandler.WriteToken(token)
_apiUrl + "Identity/Login"
[HttpPost]
[Route("Login")]
public async Task<IActionResult> Login([FromBody] UserLoginRequest request)
{
var authResponse = await _identityService.LoginAsync(request.Email, request.Password);
if (!authResponse.Succes)
{
return BadRequest(new AuthFailedResponse
{
Errors = authResponse.Errors
});
}
return Ok(new AuthSuccessResponse
{
Token = authResponse.Token
});
}
So is this what you were kinda planning?It's just a localhost address. An api I set up myself.
Pass it to the user?This is where I am at now. Trying to figure out what to do with the token that I get back.
This is like SSO using an IdP, think logging in with Google.It's just a localhost address. An api I set up myself.
You should not be catching and throwing. if this is a controller method you should log the exc and return 500. Otherwise (deeper in the call stack) you must just let the exc bubble up to the controller. Dont catch if you are not adding value in the exc handlerHi guys. Please can you guys advise me on something. I have a login page going for my MVC however this "async Task" is actually messing with the way the controller is operating.
Please help me to refactor this so that I can still run these await methods but without the Controller returning an async task. The Login itself is working and returns a token. However having this function in a task is messing with the way the login page redirects to the Home controller. Please assist
C#:public async Task<bool> LoginUserAsync(string url, string userName, string password) { try { TokenRequest Token; HttpClient client = new HttpClient(); var values = new Dictionary<string, string> { { "email", "[email protected]" }, { "password", "Admin123" } }; var content = new StringContent(JsonConvert.SerializeObject(values), Encoding.UTF8, "application/json"); var response = await client.PostAsync(url, content); var responseString = await response.Content.ReadAsStringAsync(); Token = Newtonsoft.Json.JsonConvert.DeserializeObject<TokenRequest>(responseString); client.DefaultRequestHeaders.Add("Authorization", "Bearer " + Token.token); } catch(Exception ex) { throw ex; } return true; }
This is the method behing PostAsync
C#:public async Task<T> PostAsync<T>(string methodUrl, object model) { HttpClient client = new HttpClient(); // Now serialzize the object to json string jsonData = JsonConvert.SerializeObject(model); // Create a content HttpContent content = new StringContent(jsonData); content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); // Make a request var response = await client.PostAsync(methodUrl, content); var responseAsString = await response.Content.ReadAsStringAsync(); // Deserialize the coming object into a T object T obj = JsonConvert.DeserializeObject<T>(responseAsString); return obj; }