ASP.NET MVCのAuthorizeAttributeを拡張して、問題のデータのロールメンバーシップまたは「所有権」に基づくユーザーの承認の概念をサポートするようにします。データアクセスにLINQ2SQLを使用しています。 役割を使用したasp.net mvc承認にも同様の質問があります 。
EntityProperty、UserProperty、RouteParameter、およびJoinTableTypeパラメータを拡張されたAuthorizeAttributeクラスに追加することを考えています。最初の2つは、チェックする結合テーブルのプロパティの名前です。 RouteParameterは、EntityPropertyの値を一致させるために抽出するルートパラメーターの名前です。現在のユーザー名を使用して、ユーザーのテーブルからユーザーIDを取得します。 JoinTableTypeパラメータは、ルートパラメータの値とユーザーIDが一致する必要のあるEntityとUserPropertiesを含むデータコンテキスト内のテーブルのタイプになります。
基本的な考え方は、擬似コードで:
if authorizecore result is true
user is granted access based on role
else if user is not authenticated
redirect to logon
else if user is related to request
user is granted access based on relation
else
user is not authorized, redirect to not authorized error view
関連テストは次のようになります。
result = false
find the matching user from user name
find the entity property value in route data
if user exists and entity property value exists
get table from context matching join table type
if table exists
find row in table matching user id and entity property value
if row exists
result = true
endif
endif
endif
return result
私の質問は、LINQクエリを作成するときに型とプロパティ名をどのように使用するのですか?それとも、 object
と反射を使ってこれをすべて行う必要がありますか?他の提案も同様に高く評価されるように、これをより簡単にする方法に関するアイデアを本当に探しています。これを他のアクションの処理方法と一致させるために、チェックをアクションに直接埋め込むよりも、属性を使用したいと思います。
VS2008サンプルのDynamic Linq拡張機能を使用して、これをかなり合理的な方法で行うことができました。以下は、上記の2番目の疑似コードサンプルを表すコードです。最初の単体テストに合格しましたが、より堅牢にする必要があります。
使用法:
[RoleOrMemberAuthorization( UserTable = "Participants",
UserNameProperty = "UserName",
UserSelectionProperty = "ParticipantID",
JoinTable = "GroupLeaders",
EntityProperty = "GroupID",
UserEntityProperty = "ParticipantID",
RouteParameter = "id",
Roles = "SuperUser, ViewGroups" )]
次のように呼び出されます:
else if (IsRelated( filterContext,
this.GetTable( dc, this.JoinTable ),
this.GetTable( dc, this.UserTable ) ))
{
SetCachePolicy( filterContext );
}
関連ソース:
protected bool IsRelated( AuthorizationContext filterContext,
IQueryable joinTable,
IQueryable userTable )
{
bool result = false;
try
{
object entityIdentifier = filterContext.RouteData
.Values[this.RouteParameter];
object userIdentifier = this.GetUserIdentifer( filterContext, userTable );
if (userIdentifier != null && entityIdentifier != null)
{
result = joinTable.Where( this.EntityProperty + "=@0 and "
+ this.UserEntityProperty + "=@1",
entityIdentifier,
userIdentifier )
.Count() > 0;
}
}
catch (NullReferenceException) { }
return result;
}
private object GetUserIdentifer( AuthorizationContext filterContext,
IQueryable userTable )
{
string userName = filterContext.HttpContext.User.Identity.Name;
var query = userTable.Where( this.UserNameProperty + "=@0", userName )
.Select( this.UserSelectionProperty );
object userIdentifer = null;
foreach (var value in query)
{
userIdentifer = value;
break;
}
return userIdentifer;
}
private IQueryable GetTable( DataContext context, string name )
{
PropertyInfo info = context.GetType().GetProperty( name );
if (info != null)
{
return info.GetValue( context, null ) as IQueryable;
}
else
{
return null;
}
}