I'm using identity server and would like to use a storage for the users instead of having the in memory ones so I can do user management. I want to use a NoSQL DB (MongoDB
) and I've been reading about the IUserService
(not available anymore), the ProfileService
, and ResourceOwnerPasswordValidator
, etc.
I checked this post: IdentityServer4 register UserService and get users from database in asp.net core and I did pretty much all it was said there but I couldn't get it work. Then I had a look at the AccountsController
here: https://github.com/IdentityServer/IdentityServer4.Quickstart.UI/blob/release/Quickstart/Account/AccountController.cs#L43 and realized about the comment talking about DI so I thought I could simply inject on that controller the IUserRepository
I have and
"that would be it"
However I still think there is some other stuff to do here, some other registrations and configurations that need set up in order to have it completely done.
My question would be whether my code would just be enough to achieve what I want to achieve or whether I still need to implement my own IProfileService, etc. I checked some AspNet identity examples but to me is unclear as to what's the scope of the whole set up.
For reference, this is what I have on my Login method:
/// <summary>
/// Handle postback from username/password login
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginInputModel model, string button)
{
if (button != "login")
{
// the user clicked the "cancel" button
var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
if (context != null)
{
// if the user cancels, send a result back into IdentityServer as if they
// denied the consent (even if this client does not require consent).
// this will send back an access denied OIDC error response to the client.
await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);
// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
return Redirect(model.ReturnUrl);
}
else
{
// since we don't have a valid context, then we just go back to the home page
return Redirect("~/");
}
}
if (ModelState.IsValid)
{
// validate username/password against in-memory store
var user = await _userRepository.GetUserAsync(model.Username);
//TODO: validate properly, this is just to get this working
if (user.Password == model.Password)
{
await _events.RaiseAsync(new UserLoginSuccessEvent(user.Id, user.Id, user.Id));
// only set explicit expiration here if user chooses "remember me".
// otherwise we rely upon expiration configured in cookie middleware.
AuthenticationProperties props = null;
if (AccountOptions.AllowRememberLogin && model.RememberLogin)
{
props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
};
};
// issue authentication cookie with subject ID and username
await HttpContext.SignInAsync(user.Id, user.Id, props);
// make sure the returnUrl is still valid, and if so redirect back to authorize endpoint or a local page
// the IsLocalUrl check is only necessary if you want to support additional local pages, otherwise IsValidReturnUrl is more strict
if (_interaction.IsValidReturnUrl(model.ReturnUrl) || Url.IsLocalUrl(model.ReturnUrl))
{
return Redirect(model.ReturnUrl);
}
return Redirect("~/");
}
await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));
ModelState.AddModelError("", AccountOptions.InvalidCredentialsErrorMessage);
}
// something went wrong, show form with error
return View(model);
}
Thanks in advance.