Ho un progetto MVC 6 (vNext) e sto giocando con l'identità di ASP.NET. Nel mio caso non voglio usare la componente build-in che utilizza EF (SignInManager, UserManager, UserStore). Ho un database esterno e voglio solo fare una ricerca username/password e restituire un cookie valido. Così ho iniziato a scrivere le mie lezioni.ASP.NET 5 Identity - SignInManager personalizzato
public class MyUser
{
public string Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string PasswordHash { get; set; }
}
public class MyUserStore : IUserStore<MyUser>, IUserPasswordStore<MyUser>
{
...
}
Nella classe MyUserStore
sto utilizzando lista hard-coded di utenti come il mio negozio (solo a scopo di test). E ho annullato alcuni metodi solo per restituire i dati dal negozio hard-coded.
public class MyUserManager : UserManager<MyUser>
{
public MyUserManager(
IUserStore<MyUser> store,
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<MyUser> passwordHasher,
IEnumerable<IUserValidator<MyUser>> userValidators,
IEnumerable<IPasswordValidator<MyUser>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IEnumerable<IUserTokenProvider<MyUser>> tokenProviders,
ILoggerFactory logger,
IHttpContextAccessor contextAccessor) :
base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, tokenProviders, logger, contextAccessor)
{
}
}
Qui ho fatto i metodi CheckPasswordAsync
e VerifyPasswordAsync
per tornare true
e PasswordVerificationResult.Success
, rispettivamente, solo per il test.
public class MyClaimsPrincipleFactory : IUserClaimsPrincipalFactory<MyUser>
{
public Task<ClaimsPrincipal> CreateAsync(MyUser user)
{
return Task.Factory.StartNew(() =>
{
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
var principle = new ClaimsPrincipal(identity);
return principle;
});
}
}
public class MySignInManager : SignInManager<MyUser>
{
public MySignInManager(MyUserManager userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory<MyUser> claimsFactory, IOptions<IdentityOptions> optionsAccessor = null, ILoggerFactory logger = null)
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger)
{
}
public override Task<SignInResult> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout)
{
// here goes the external username and password look up
if (userName.ToLower() == "username" && password.ToLower() == "password")
{
return base.PasswordSignInAsync(userName, password, isPersistent, shouldLockout);
}
else
{
return Task.FromResult(SignInResult.Failed);
}
}
}
e tutto è collegato nella classe Startup
come segue:
services.AddIdentity<MyUser, MyRole>()
.AddUserStore<MyUserStore>()
.AddUserManager<MyUserManager>()
.AddDefaultTokenProviders();
E perché io non sono riuscito a creare l'oggetto MySignInManager
nel codice Startup
al fine di aggiungerlo nel DI (per l'iniezione successiva nei controller e nelle viste), lo sto creando nello MyAccountController
.
public MyAccountController(IHttpContextAccessor httpContextAccessor, UserManager<MyUser> userManager, IOptions<IdentityOptions> optionsAccessor, ILoggerFactory logger)
{
SignInManager = new MySignInManager(userManager as MyUserManager, httpContextAccessor, new MyClaimsPrincipleFactory(), optionsAccessor, logger);
}
Nel mio MyLogin
azione nel controller MyAccount
sto chiamando PasswordSignInAsync
e posso vedere che sto ottenendo il cookie con rivendicazioni codificati in esso (dal MyClaimsPrincipleFactory
). Quando provo a chiamare qualche altra azione con lo AuthorizeAttribute
su di esso, posso vedere che il cookie è nell'intestazione della richiesta ma non sono autorizzato (più precisamente, perché non ho rimosso l'autenticazione di identità predefinita ASP.NET da il modello di esempio dello studio visivo, sono reindirizzato invece all'Account/Login).
È questo il modo giusto di personalizzare l'identità di ASP.NET e cosa mi manca qui?
Inserire un punto di interruzione su questa riga return base.PasswordSignInAsync (userName, password, isPersistent, shouldLockout); e vedere cosa restituisce. La mia ipotesi è che anch'essa restituisca SignInResult.Failed. Vorrei tornare Task.FromResult (SignInResult.Success) invece di chiamare la classe base ... hth – ojf
Sì, l'ho provato. Quando ritorno con successo senza chiamare il metodo base, non ricevo il cookie. –