私が試したコードを投稿しているだけです。これは私が取ったアプローチにすぎません。しかし、セキュリティ、パフォーマンスなどに関してこれが良い考えであるかどうかを言うには、epxperts のコメントが必要です。
手順 1: IPrincipal を継承する定義済みのカスタム インターフェイス
public interface ICustomPrincipal : IPrincipal
{
string[] Roles { get; set; }
string Country { get; set; }
string Region { get; set; }
string Department { get; set; }
string CurrentProductId { get; set; }
bool HasAcceptedTerms { get; set; }
}
ステップ 2: 上記のインターフェイスを使用してカスタム プリンシパルを実装する
public class CustomPrincipal : ICustomPrincipal
{
private IPrincipal principal;
public CustomPrincipal(IPrincipal principal, WindowsIdentity identity)
{
this.Identity = identity;
this.principal = principal;
}
#region IPrincipal Members
public IIdentity Identity { get; private set; }
public bool IsInRole(string role)
{
return (principal.IsInRole(role));
}
public string Department { get; set; }
public string[] Roles { get; set; }
public string Country { get; set; }
public string Region { get; set; }
public string CurrentProductId { get; set; }
public bool HasAcceptedTerms { get; set; }
#endregion
}
ステップ 3: 独自のロール プロバイダーを定義します。また、このプロバイダーの web.config エントリを作成し、これを既定のプロバイダーとして設定します。
public class MyCustomRoleProvider : RoleProvider
{
List<string> _roles = new List<string> { "System Administrators", "Product Administrators", "Users", "Guests" };
public override string[] GetRolesForUser(string username)
{
//TODO: Get the roles from DB/Any other repository and add it to the list and return as array
return _roles.ToArray();
}
public override bool IsUserInRole(string username, string roleName)
{
if (_roles.Contains(roleName))
{
//this.Department = "My Department";
return true;
}
else
return false;
}
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override string ApplicationName
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public override void CreateRole(string roleName)
{
throw new NotImplementedException();
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
throw new NotImplementedException();
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
throw new NotImplementedException();
}
public override string[] GetAllRoles()
{
throw new NotImplementedException();
}
public override string[] GetUsersInRole(string roleName)
{
throw new NotImplementedException();
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override bool RoleExists(string roleName)
{
throw new NotImplementedException();
}
}
ステップ 4: 以下のイベントを実装
注: 追加のユーザー情報を FormsAuthenticationTicket にシリアル化しています。Web サイトで Windows 認証が有効になっています。
protected void WindowsAuthentication_OnAuthenticate(Object source, WindowsAuthenticationEventArgs e)
{
if (null == Request.Cookies.Get("authCookie"))
{
var userId = e.Identity.Name;
//TODO: You may need to get the user details like country, region etc. from DB. For simplicity, I have just assigned user roles (multiple) property
//Instead of string array, you should use your own Class to hold this custom data and then serialize
string[] userRoles = new string[] { "System Administrators", "Users" };
StringWriter writer = new StringWriter();
XmlSerializer xs = new XmlSerializer(typeof(string[]));
xs.Serialize(writer, userRoles);
FormsAuthenticationTicket formsAuthTicket =
new FormsAuthenticationTicket(
1,
userId,
DateTime.Now,
DateTime.Now.AddMinutes(20),
false,
writer.ToString());
var encryptedTicket = FormsAuthentication.Encrypt(formsAuthTicket);
HttpCookie httpCookie = new HttpCookie("authCookie", encryptedTicket);
Response.Cookies.Add(httpCookie);
}
}
ステップ 5: PostAuthenticateRequest イベントを使用して、RolePrincipal を CustomPrincipal でラップします。これは、アプリケーションのどの部分からでもデータにアクセスできるように、プリンシパル オブジェクトにデータを保持するために必要です。WINDOWS プリンシパル オブジェクトをラップするために Application_AuthenticateRequest を使用しないでください。ロール プロバイダーを有効にすると、ASP.NET は実際に WINDOWS プリンシパルをロール プリンシパルに置き換えます。
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Context.Request.Cookies.Get("authCookie");
FormsAuthenticationTicket formsAuthenticationTicket = FormsAuthentication.Decrypt(authCookie.Value);
CustomPrincipal newUser = new CustomPrincipal(User, (WindowsIdentity)User.Identity);
StringReader sr = new StringReader(formsAuthenticationTicket.UserData);
XmlSerializer xs = new XmlSerializer(typeof(string[]));
object ret = xs.Deserialize(sr);
newUser.Roles = (string[]) ret;
Context.User = newUser;
}
Preben が提案したように、ユーザーが別の製品に切り替えるたびに Cookie を更新します。
これが、Windows 認証と組み合わせて追加のユーザー データを保存しようとしている人に役立つことを願っています。
目標を達成するためのより良いアプローチがあれば教えてください。