I have Authentication API (jwt) for authentication users. Using this for several clients and am in the process of adding the second client now.. firs one works as it should. I have determent that the problem is with this section:
var _authorizePolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
var _serviceProvider = builder.Services.BuildServiceProvider();
var _authenticationSettings = _serviceProvider.GetService<IAuthenticationSettings>();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddCookie(JwtBearerDefaults.AuthenticationScheme,
options => {
options.LoginPath = _authenticationSettings.LoginPath;
options.AccessDeniedPath = _authenticationSettings.AccessDeniedPath;
options.Events = new CookieAuthenticationEvents
{
// Check if JWT needs refreshment
OnValidatePrincipal = RefreshTokenMonitor.ValidateAsync
};
options.Cookie.Name = "MainAppCookie";
}
);
builder.Services.AddMvc(config =>
{
config.Filters.Add(new AuthorizeFilter(_authorizePolicy));
})
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
})
.AddViewOptions(options => options.HtmlHelperOptions.ClientValidationEnabled = true);
I have the same code (different name for the Cookie) is the first application and it works fine there.
Here you have the AccountController:
public class AccountController : Controller
{ private readonly ISecurityManager _securityManager;
public AccountController(ISecurityManager securityManager)
{
_securityManager = securityManager;
}
public async Task<IActionResult> Login()
{
return View(new LoginViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login([FromForm] LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (!ModelState.IsValid)
{
ViewBag.ErrorMessage = "Input data incorrect. Please try again";
ModelState.AddModelError(string.Empty, "Invalid login form");
return View(model);
}
if (await _securityManager.LoginUser(model.Email, model.Password))
return RedirectToLocal(returnUrl);
else
{
ViewBag.ErrorMessage = "Invalid login attempt.";
return View(model);
}
return View(model);
}
public async Task<IActionResult> AccessDenied()
{
return View();
}
[HttpGet]
[Route("account/password/forgot")]
public async Task<IActionResult> ForgotPassword()
{
return View(new ForgotPasswordModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ForgotPasswordSubmit(ForgotPasswordModel model)
{
return RedirectToAction(nameof(ForgotPasswordConfirmation));
}
[Route("account/password/confirmation")]
public async Task<IActionResult> ForgotPasswordConfirmation()
{
return View();
}
[HttpGet]
[Route("account/password/reset")]
public async Task<IActionResult> ResetPassword()
{
return View(new PasswordResetModel());
}
[HttpPost]
public async Task<IActionResult> ResetPasswordSubmit(PasswordResetModel model)
{
return RedirectToAction(nameof(Login), new { });
}
public async Task<IActionResult> LogOut()
{
//await _securityManager.LogOut();
return RedirectToAction(nameof(Login));
}
// Prevent session stealing
private IActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
return Redirect(returnUrl);
else
return RedirectToAction(nameof(HomeController.Index), "Home");
}
}
Here you have the actual login:
private async Task<bool> Login(AuthResult token)
{
if(token.Token.IsNullOrEmpty())
return false;
await LogOut();
var _tokenHandler = new JwtSecurityTokenHandler();
var _tokenSettings = _jwtTokenValidationSettings.CreateTokenValidationParameters();
var _principal = _tokenHandler.ValidateToken(token.Token, _tokenSettings, out var _validatedToken);
var _identity = _principal.Identity as ClaimsIdentity;
var _securityToken = _tokenHandler.ReadToken(token.Token) as JwtSecurityToken;
var _extraClaims = _securityToken.Claims.Where(c => !_identity.Claims.Any(x => x.Type == c.Type)).ToList();
_extraClaims.Add(new Claim("jwt", token.Token));
_extraClaims.Add(new Claim("refreshToken", token.RefreshToken));
_identity.AddClaims(_extraClaims);
var _authenticationProperties = new AuthenticationProperties()
{
IssuedUtc = _identity.Claims.First(c => c.Type == JwtRegisteredClaimNames.Iat)?.Value.ToInt64().ToUnixEpochDate(),
ExpiresUtc = _identity.Claims.First(c => c.Type == JwtRegisteredClaimNames.Exp)?.Value.ToInt64().ToUnixEpochDate(),
IsPersistent = true
};
await _httpContext.SignInAsync(JwtBearerDefaults.AuthenticationScheme, _principal, _authenticationProperties);
return _identity.IsAuthenticated;
}
And to clarify further... This is a error I get:

CodePudding user response:
Your LoginControler (or several of its actions) needs to have [AllowAnonymous] to allow it to bypass the auth checks. Otherwise, the user won't have permission to view those routes.
CodePudding user response:
The error was actually in [AllowAnonymous] attribute in AccountController. Removed it and build the project, added the attribute again. Works like a charm :)


