2日間のプロジェクトを実行する前に、認証は比較的頭痛場所となっていることを思い出してください。
だから、身元を確認、フォーム認証を開始し、コンテンツの一部を読み取るために時間を割いて、プロセスは単純なブラウザですが、コンセプトは、一部が深まっ有すると考えることができる前に。
実際には、これら二つの天才は、フォーム認証は、すでに.NETで過去のものである、知っている、アイデンティティが交換されています。それでも後、私は、フォーム認証を読んで、全体のプロセスの認定は、いくつか理解しているにもあるが、ここでいくつかのアイデンティティ関連のコンテンツを降りるです。
Owin
Owinアイデンティティは、フレームワークに基づいています。Owin実際kantanaと呼ばれるその.NETを達成するための仕様で、実際に彼らが使用するには、私は基本的に相互接続されていると思います。
OwinはもはやIIS要求パイプラインに依存しませんが、すでに.NETコアの練習に類似している個々のコンポーネントをカスタマイズするための登録メカニズム。
OwinとIIS
Owinは、IIS上で実行することができます、また、独立して実行することができ、OwinはIISベース、Owin依存する場合、独自のSelfHostコンポーネントと独立して動作するMicrosoft.Owin.Host.SystemWeb
ライブラリはIISの統合を完了します。
IIS Global.asax
とのOwin StartUp
コールバックも同時に存在すること、それが呼び出されます。
IISに統合された場合は、初期化コールOwin、ほとんどのApplication_Startイベントの後にトリガ。
Owin起動クラス
パイプラインOwin始まるクラスコンフィギュレーション・プロセスに配置されています。
1は、Web.configファイルのAppSettingsノードに指定されている2つの構成が、あります。
<add key="owin:AppStartup" value="起始类" />
含有させることにより、別のプロパティ設定、Configuration
クラスメソッドにラベリングプロパティを
[assembly: OwinStartup(typeof(StartupDemo.TestStartup))]
身元
アイデンティティは、ある程度、元のフォーム認証を交換していますが、Owinを使用しない場合、私はまだフォーム認証を使用することを理解する必要があります。
アイデンティティは、ネットワーク環境下で、第三者認証の出現(グーグル、FBなど)、二要素認証(2FA)需要に応じて、実際に、フォームの伝統的な方法は、可能性が低い拡大することです。
ある程度SOのこの部分への言及は、この質問への答え
アイデンティティ成分が増加
Owin依存離れて、アイデンティティもEntityFrameworkに、いくつかのコンポーネントNugetが必要です。
- Microsoft.AspNet.Identity.Owin
- Microsoft.AspNet.Identity.EntityFramework
- Microsoft.Owin.Host.SystemWeb
MySQLを使用する必要がある場合、また、あなたがインストールする必要があります
- MySql.Data.Entity
コンフィギュレーションと初期化
プロファイル
Web.configファイルの構成は、いくつかのコンテンツを追加する必要があります
エンティティのインストールで自動増加のこの部分にエンティティバックは、実際には、手動で変更する必要はありません。
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
具体的には、Iの使用はそれほどのAppSettingsにノードが私のポータル配置を高め、Owinスタートアップコンフィギュレーションに基づいています
<add key="owin:AppStartup" value="Demo.WEBUI.IdentityConfig" />
エンティティのユーザー情報を硬化させることによりアイデンティティが、一般的な慣習の.NETの一部である、のConnectionStringエンティティを使用し設定する必要があります。
<connectionStrings>
<add name="DefaultConnection" connectionString="server=localhost;database=dbname;uid=root;pwd=123456" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
通常はデフォルトでインストールMySQLのサポート内のエンティティの増加は、それがのSQLServerです。
<entityFramework>
<defaultConnectionFactory type="MySql.Data.Entity.MySqlConnectionFactory, MySql.Data.Entity.EF6" />
<providers>
<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6, Version=6.10.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
また、エンティティ、DBPROVIDERを増やし、このノードは言葉なしで、より良い説明を見つけることではなく、しません。
<system.data>
<DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient"></remove>
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.10.8.0" />
</DbProviderFactories>
</system.data>
補助クラス
ユーザー
ユーザークラスのアイデンティティは、ユーザーテーブルに参加するカスタムフィールドを追加、また彼の財団から拡張することができ、直接IdentityUserを使用することができ、私は三つのフィールドを追加しました。
public class ApplicationUser : IdentityUser
{
public virtual DateTime? LastLoginTime { get; set; }
public virtual DateTime? RegistrationTime { get; set; }
public virtual bool IsEnabled { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
ユーザー管理
ここでは、このようなパスワードの強度、クッキーの有効期限として、ユーザー認証の設定を構成しています
public class ApplicationUserManager : UserManager<ApplicationUser>
{
private IUserStore<ApplicationUser> _store;
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
_store = store;
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = true,
RequireUniqueEmail = false
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 4,
RequireNonLetterOrDigit = false,
RequireDigit = false,
RequireLowercase = false,
RequireUppercase = false,
};
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = false;
//manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
//manager.MaxFailedAccessAttemptsBeforeLockout = 5;
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
}
ログ管理
前のステップに依存するユーザーのログインメソッド呼び出し、ApplicationUserManager
public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
{
return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
}
public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
{
return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
}
}
ロール管理
ここで私はより多くの機能拡張をしませんでした。アイデンティティ自体は、ロールベースのことはできませんが、クレームの権限制御に関する。
そのため、管理の役割は必要ありません。
public class ApplicationRoleManager : RoleManager<IdentityRole, string>
{
public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
return new ApplicationRoleManager(new RoleStore<IdentityRole, string, IdentityUserRole>(context.Get<ApplicationDbContext>()));
}
}
初期クラス
.NET MVC認証を使用して新しいプロジェクトが自動的に初期クラスを追加します場合。
自動的に作成され、機能(ローカルのみログイン)の一部を削除する必要はありません対私のアイデンティティはコピーから初期クラスに既存のプロジェクト、初期化関数に追加します。
public void Configuration(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Login/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
//app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
//app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
//app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
使用
主な焦点ApplicationUserManager
、ApplicationSignInManager
周りのユーザー登録ログインおよび他の操作ApplicationRoleManager
のユーザー権限管理。
登録
基本ロジックまたはデフォルトのフレームワーク対登録し、いくつかのカスタマイズされた機能が追加されていますから。
ここで私は、ユーザーの役割の設定を増加し、平均的なユーザーのために、その後、最初の管理者として登録されたユーザを定義します。
アプリケーションは、他の場所では操作がユーザのロールを介して行うことができる判断するために来ます。
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
try
{
var user = new ApplicationUser
{
UserName = model.UserName,
Email = model.Password,
IsEnabled = false, //default disabed
LastLoginTime = DateTime.Now,
RegistrationTime = DateTime.Now
};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
//init roles
if (!RoleManager.Roles.Any())
{
await RoleManager.CreateAsync(new IdentityRole(UserRole.NORMAL));
await RoleManager.CreateAsync(new IdentityRole(UserRole.ADMINISTRATOR));
}
var adminRoleId = (await RoleManager.FindByNameAsync(UserRole.ADMINISTRATOR)).Id;
var hasAdmin = UserManager.Users.Any(p => p.Roles.Any(x => x.RoleId == adminRoleId));
var userRole = UserRole.NORMAL;
if (!hasAdmin)
{
userRole = UserRole.ADMINISTRATOR;
//make the first admin enabled
user.IsEnabled = true;
await UserManager.UpdateAsync(user);
}
await UserManager.AddToRoleAsync(user.Id, userRole);
//let the user manual log in
//await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");
return RedirectToAction("Login", "Login");
}
AddErrors(result);
}
catch (System.Data.Entity.Validation.DbEntityValidationException e)
{
Console.WriteLine(e.ToString());
throw e;
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
ログイン
私は、ユーザーを定義すると、ユーザのログイン時間と、ユーザーが有効になっている場合、カスタムフィールドを追加します。
ここでは、2つのフィールドが使用してきました。
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await UserManager.FindByNameAsync(model.UserName);
if (null == user)
{
ModelState.AddModelError("", "登录失败.");
return View(model);
}
if ((!await UserManager.IsInRoleAsync(user.Id, UserRole.ADMINISTRATOR)) && !user.IsEnabled)
{
ModelState.AddModelError("", "账户未启用,请联系管理员.");
return View(model);
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
user.LastLoginTime = DateTime.Now;
await UserManager.UpdateAsync(user);
return RedirectToLocal(returnUrl);
default:
ModelState.AddModelError("", "登录失败.");
return View(model);
}
}
いくつかの拡張機能の使用
パスワードのリセット
より安全なパスワード・リセット・ロジックはメール等、電話、であるが、私はシステムにあった、最も簡単な方法は、直接管理者のセットを使用することです。
これは、トークンへのより一般的には、手動でパスワードを変更するためにユーザを接続することで、接続によってユーザに送信することができるです。
[HttpPost]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
if (!IsAdmin && !model.UserName.Equals(User.Identity.Name))
{
ModelState.AddModelError("", "无效的用户名");
return View();
}
var user = await UserManager.FindByNameAsync(model.UserName);
if (user == null)
{
return View();
}
var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var result = await UserManager.ResetPasswordAsync(user.Id, token, model.Password);
if (!result.Succeeded)
{
AddErrors(result);
}
else
{
ViewBag.msg = "修改成功!";
}
return View();
}
アクセス制御
実際には、途中でクレームに基づいていますが、このシステムは、やや複雑なクレームによって制御される、比較的簡単ですので、私は役割に直接的な方法を使用していました。
二つの方法、最初のユーザーのプロパティコントローラ/ WebViewPageがによって内部であり、User.IsInRole(UserRole.ADMINISTRATOR);
ユーザー権限を決定するための方法は、ここに入ってくるロール名はRoleIdは、ではありません。
もう一つはApplicationUserManagerのあるUserManager.GetRoles(user.Id)
すべてのロール名のユーザーを取得し、その後、役割によって所望のものを決定することができ、方法。
問題
MySQLの接続が失敗しました
時には NuGet 8.xxバージョンがシステムにインストールされますMySql.Data
、検索、私は、多くの人々は、このバージョンで問題が発生していること6. XXバージョンへのダウングレードを見つけました。
リメンバー・ミー機能
ユーザーが通話をログに記録すると、この問題は、解決されていません
var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
ここでの3番目の引数は、有効なログオン設定、集合論でfalse
、制限期間はクッキーCurrentSessionあり、そしてtrue
、その後、時間の長い期間になります。
実際に私たちが渡されたことが判明しtrue
、有効期限が15日(これは比較的正常)であり、渡されfalse
、有効になりますN/A
有効期限が切れることはありません。発見を解決する方法はありません。