2015-07-07 15 views
21

मेरे पास एक एमवीसी 6 प्रोजेक्ट (vNext) है और मैं एएसपी.NET पहचान के साथ खेल रहा हूं। मेरे मामले में मैं बिल्ड-इन सामान का उपयोग नहीं करना चाहता जो ईएफ (साइनइनमेनर, उपयोगकर्ता प्रबंधक, उपयोगकर्तास्टोर) का उपयोग करता है। मेरे पास एक बाहरी डेटाबेस है और मैं सिर्फ उपयोगकर्ता नाम/पासवर्ड लुकअप बनाना चाहता हूं और एक वैध कुकी वापस कराना चाहता हूं। इसलिए मैंने अपनी कक्षाएं लिखना शुरू कर दिया।एएसपी.नेट 5 पहचान - कस्टम साइनइन प्रबंधक

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> 
{ 
    ... 
} 

MyUserStore कक्षा में मैं अपने स्टोर के रूप में (केवल परीक्षण प्रयोजनों के लिए) उपयोगकर्ताओं की हार्ड-कोडेड सूची का उपयोग कर रहा हूँ। और मैं हार्ड-कोडेड स्टोर से डेटा वापस करने के लिए कुछ विधियों को ओवरराइड करता हूं।

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) 
    { 
    } 
} 

यहाँ मैं तरीकों CheckPasswordAsync और VerifyPasswordAsync क्रमशः true और PasswordVerificationResult.Success वापस जाने के लिए सिर्फ परीक्षा के लिए बनाया है। इस प्रकार

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); 
     } 
    } 
} 

और सब कुछ Startup कक्षा में झुका है:

services.AddIdentity<MyUser, MyRole>() 
      .AddUserStore<MyUserStore>() 
      .AddUserManager<MyUserManager>() 
      .AddDefaultTokenProviders(); 

और क्योंकि मैं यह डि में जोड़ने के लिए Startup कोड में MySignInManager वस्तु बनाने के लिए प्रबंधन नहीं किया (नियंत्रकों और विचारों में बाद में इंजेक्शन के लिए), मैं इसे MyAccountController में बना रहा हूं।

public MyAccountController(IHttpContextAccessor httpContextAccessor, UserManager<MyUser> userManager, IOptions<IdentityOptions> optionsAccessor, ILoggerFactory logger) 
{ 
    SignInManager = new MySignInManager(userManager as MyUserManager, httpContextAccessor, new MyClaimsPrincipleFactory(), optionsAccessor, logger); 
} 

MyAccount नियंत्रक में मेरी MyLogin कार्रवाई में मैं PasswordSignInAsync बोल रहा हूँ और मैं देख सकता हूँ कि मैं इसे में एन्कोड दावे के साथ कुकी (MyClaimsPrincipleFactory से) हो रही है। जब मैं AuthorizeAttribute पर कुछ अन्य क्रियाओं को कॉल करने का प्रयास करता हूं तो मैं देख सकता हूं कि कुकी अनुरोध हेडर में है लेकिन मैं अनधिकृत हूं (अधिक सटीक, क्योंकि मैंने अंतर्निहित डिफ़ॉल्ट एएसपी.NET पहचान प्रमाणीकरण को नहीं हटाया है दृश्य स्टूडियो नमूना टेम्पलेट, मुझे इसके बजाय खाता/लॉगिन पर रीडायरेक्ट किया गया है)।

क्या यह एएसपी.नेट पहचान को अनुकूलित करने का सही तरीका है और मैं यहां क्या खो रहा हूं?

+0

इस लाइन वापसी आधार पर एक ब्रेकपॉइंट रखें। पासवर्ड साइनइनएसिंक (उपयोगकर्ता नाम, पासवर्ड, isPersistent, shouldLockout); और देखें कि यह क्या लौटाता है। मेरा अनुमान है कि यह भी SignInResult लौट रहा है। विफल। मैं बेस क्लास को कॉल करने के बजाय टास्क.फ्रोआरसल्ट (साइनइन रिसेट। सिक्योर) वापस कर दूंगा ... एचएच – ojf

+0

हाँ मैंने कोशिश की। जब मैं बेस विधि को कॉल किए बिना सफलता वापस कर रहा हूं, तो मुझे कुकी नहीं मिल रही है। –

उत्तर

5

मेरी परियोजना में मेरे पास ईएफ का उपयोग किए बिना पहचान का एक कार्यान्वयन कार्यान्वयन है। मुझे लगता है कि शायद आप की जरूरत से अधिक लागू कर रहे हैं। UserManager और SignInManager ईएफ से बंधे नहीं हैं। यदि आप चाहें तो आप उन्हें लागू कर सकते हैं लेकिन आपको केवल ईएफ से दूर जाने की आवश्यकता नहीं है। यदि आपको परीक्षण के लिए हार्ड कोड किए गए पासवर्ड को सत्यापित करने की आवश्यकता है तो आपको केवल उपयोगकर्तास्टोर और रोलस्टोर और शायद पासवर्डहेशर को लागू करने की आवश्यकता है।

services.TryAdd(ServiceDescriptor.Scoped<IUserStore<SiteUser>, UserStore<SiteUser>>()); 
services.TryAdd(ServiceDescriptor.Scoped<IUserPasswordStore<SiteUser>, UserStore<SiteUser>>()); 
services.TryAdd(ServiceDescriptor.Scoped<IUserEmailStore<SiteUser>, UserStore<SiteUser>>()); 
services.TryAdd(ServiceDescriptor.Scoped<IUserLoginStore<SiteUser>, UserStore<SiteUser>>()); 
services.TryAdd(ServiceDescriptor.Scoped<IUserRoleStore<SiteUser>, UserStore<SiteUser>>()); 
services.TryAdd(ServiceDescriptor.Scoped<IUserClaimStore<SiteUser>, UserStore<SiteUser>>()); 
services.TryAdd(ServiceDescriptor.Scoped<IUserPhoneNumberStore<SiteUser>, UserStore<SiteUser>>()); 
services.TryAdd(ServiceDescriptor.Scoped<IUserLockoutStore<SiteUser>, UserStore<SiteUser>>()); 
services.TryAdd(ServiceDescriptor.Scoped<IUserTwoFactorStore<SiteUser>, UserStore<SiteUser>>()); 
services.TryAdd(ServiceDescriptor.Scoped<IRoleStore<SiteRole>, RoleStore<SiteRole>>()); 
services.TryAdd(ServiceDescriptor.Scoped<IUserClaimsPrincipalFactory<SiteUser>, SiteUserClaimsPrincipalFactory<SiteUser, SiteRole>>()); 
services.TryAdd(ServiceDescriptor.Transient<IPasswordHasher<SiteUser>, SitePasswordHasher<SiteUser>>()); 
services.AddIdentity<SiteUser, SiteRole>(); 
ऊपर

आइटम मैं इकाई की रूपरेखा बायपास करने के लिए लागू करने कर रहा हूँ पता चलता है, उदाहरण के लिए मेरी AccountController के लिए

UserManager<SiteUser> userManager, 
      SignInManager<SiteUser> signInManager 

जो मानक पहचान UserManager और SignInManager मैं नहीं था कि कर रहे हैं निर्माता पैरामीटर लेता है डि साथ सेटअप सेवा वे इस लाइन द्वारा मेरे लिए पंजीकृत हैं:

services.AddIdentity<SiteUser, SiteRole>(); 

आपकर सकते हैं। यह पहचान का हिस्सा है जो ईएफडीडेंटिटी का हिस्सा नहीं है। आप देख सकते हैं कि मैंने IUserClaimsPrincipalFactory भी लागू किया है। एकमात्र कारण जिसे मैंने कार्यान्वित किया था, कुछ कस्टम दावों को जोड़ना था, मुझे ईएफ से दूर जाने के लिए ऐसा करने की आवश्यकता नहीं थी।

+0

मुझे वास्तव में आईरोलस्टोर को लागू करने की आवश्यकता नहीं है क्योंकि यह वास्तव में स्टार्टर वेब ऐप कोड में कहीं भी उपयोग नहीं किया जाता है। मेरा "कार्यान्वयन" बस हर विधि में NotImplementedException फेंकता है लेकिन मुझे अपवाद का सामना नहीं करना पड़ता क्योंकि इसका कहीं भी उपयोग नहीं किया जाता है। संभावित रूप से वीएस वेब ऐप टेम्पलेट के भविष्य के संस्करणों में भूमिकाओं को प्रबंधित करने के लिए नियंत्रक/विचार होंगे और इसकी आवश्यकता होगी लेकिन अब नहीं। –

+0

ठीक है, मैंने अपना कस्टम 'साइनइन प्रबंधक' और 'उपयोगकर्ता प्रबंधक' हटा दिया है। फिर भी जब मैं 'प्राधिकरण' विशेषता के साथ कार्रवाई करने का प्रयास करता हूं तो मुझे 302 मिल रहा है और यह मुझे/खाता/लॉगिन - डिफ़ॉल्ट पर रीडायरेक्ट करता है। लेकिन मेरे पास MyAccountController मेरे कस्टम IUserStore, MyUser, आदि के साथ काम कर रहा है .... –

+0

मुझे एहसास हुआ कि लॉगिन करने के बाद मेरे पास 'User.Identity' ऑब्जेक्ट में मेरा 'दावा Identity' है। लेकिन 'प्रमाणीकृत' संपत्ति 'झूठी 'है। फिडलर में मैं देख सकता हूं कि कुकी वहां है और यह प्रत्येक अनुरोध के साथ पारित हो जाती है। –

3

यहां मुद्दा यह था कि मैंने ClaimsIdentity ऑब्जेक्ट के AuthenticationType प्रदान नहीं किया था। This blog post ने मेरी मदद की।

सही पर सेट किया IsAuthenticated है के लिए, आपको ctor में एक प्रमाणीकरण प्रकार निर्दिष्ट करना होगा:

वर आईडी = नए ClaimsIdentity (दावा है, "कस्टम");

5

मुझे कस्टम SignInManager का उपयोग करने की भी समस्याएं थीं और लागू करने के बाद वास्तव में आसान हो गईं।

Startup.cs में, services.Identity

services.AddIdentity<ApplicationUser, IdentityRole>() 
    .AddEntityFrameworkStores<ApplicationDbContext>() 
    .AddDefaultTokenProviders(); 

के डिफ़ॉल्ट कार्यान्वयन के बाद आप केवल में इंजेक्षन करने की जरूरत है निर्मित डि निम्नलिखित:

services.AddScoped<SignInManager<MyApplicationUser>, MySignInManager>(); 

डिफ़ॉल्ट SignInManager कस्टम एक एक करके overwrited है ।

1

आप इस प्रकार अपने Startup.ConfigureServices विधि के भीतर IdentityBuilder.AddSignInManager विधि का उपयोग कर निर्भरता इंजेक्शन के लिए एक कस्टम SignInManager रजिस्टर कर सकते हैं:

services.AddIdentity<MyUser, IdentityRole<int>>() 
    .AddUserStore<UserStore<MyUser, IdentityRole<int>, SqlContext, int>>() 
    .AddRoleStore<RoleStore<IdentityRole<int>, SqlContext, int>>() 
    .AddSignInManager<SignInManager<MyUser>>() 
    .AddDefaultTokenProviders(); 

कोई कारण नहीं है कि SignInManager आप को लागू किया है उसी में डि के लिए पंजीकृत नहीं किया जा सकता है मार्ग।

संबंधित मुद्दे