LINQ에서 SQL을 사용한 ASP.NET MVC : 저장소의 엔터티에 승인을 구현하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1429661

문제

도메인 중심 디자인을 염두에두고 저장소에서 사용자 인증을 어떻게 구현 하시겠습니까? 구체적으로, 사용자가 제공 한 로그인이 볼 수있는 데이터를 어떻게 제한 하시겠습니까?

주어진 상점 관리자가 일부 제품 만 유지 관리하는 제품을 저장하는 전자 상거래 몰이 있다고 가정 해 봅시다. 이 경우 주어진 로그인으로 모든 제품을 볼 수는 없습니다.

질문:

  1. Repo의 모든 제품을 선택한 다음 필터를 사용하여 반환되는 제품을 제한 하시겠습니까? Like GetProducts("keyword: boat").restrictBy("myusername")?
  2. 저장소 내에서 ControlLerContext에서 로그인을 읽고 수동적으로 필터 결과를 읽으시겠습니까?
  3. 사용자 역할과 액세스 할 수있는 엔티티 간의 관계를 어떻게 저장 하시겠습니까? 엔티티 키와 역할을 각 상점 관리자가 액세스 할 수있는 각 제품에 대해 하나의 레코드를 보유한 엔티티 키와 역할을 간단히 저장 하시겠습니까?

코드 예제 또는 코드 예제 링크는 환상적입니다. 고맙습니다.

도움이 되었습니까?

해결책

내가 취한 압정은 현재 사용자와 요청중인 엔티티 간의 관계를 조사하는 컨트롤러 동작에 속성을 사용한 다음 조회 결과에 따라 작업을 허용하거나 비활성화하는 것입니다. 가입 테이블을 통과하는지 또는 직접적인 관계가 있는지에 따라 몇 가지 다른 속성이 있습니다. 내 경우에는 데이터 컨텍스트에 대한 반사를 사용하지만 값이 일치하는지 확인하고 확인하기 위해 저장소 (IES)를 사용합니다. 아래에 코드를 포함하겠습니다 (제대하기 위해 약간의 노력을 기울여 컴파일하지 않을 수 있습니다). 참고를 확장하여 권한이라는 개념 (조인 테이블에)도 포함 할 수 있습니다.

직접 관계 속성에 대한 코드. 현재 사용자가 레코드의 소유자인지 확인합니다 (라우팅 매개 변수의 지정된 "ID"속성은 사용자 테이블의 현재 사용자의 ID와 일치 함).

[AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false )]
public class RoleOrOwnerAuthorizationAttribute : AuthorizationAttribute
{
    private IDataContextFactory ContextFactory { get; set; }

    private string routeParameter = "id";
    /// <summary>
    /// The name of the routing parameter to use to identify the owner of the data (participant id) in question.  Default is "id".
    /// </summary>
    public string RouteParameter
    {
        get { return this.routeParameter; }
        set { this.routeParameter = value; }
    }

    public RoleOrOwnerAuthorizationAttribute()
        : this( null )
    {
    }

    // this is for unit testing support
    public RoleOrOwnerAuthorizationAttribute( IDataContextFactory factory )
    {
        this.ContextFactory = factory ?? DefaultFactory();
    }

    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException( "filterContext" );
        }

        if (AuthorizeCore( filterContext.HttpContext ))
        {
            SetCachePolicy( filterContext );
        }
        else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            // auth failed, redirect to login page
            filterContext.Result = new HttpUnauthorizedResult();
        }
        else if (filterContext.HttpContext.User.IsInRole( "SuperUser" ) || IsOwner( filterContext ))
        {
            SetCachePolicy( filterContext );
        }
        else
        {
            ViewDataDictionary viewData = new ViewDataDictionary();
            viewData.Add( "Message", "You do not have sufficient privileges for this operation." );
            filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData };
        }

    }

    private bool IsOwner( AuthorizationContext filterContext )
    {
        using (var dc = this.ContextFactory.GetDataContextWrapper())
        {
            int id = -1;
            if (filterContext.RouteData.Values.ContainsKey( this.RouteParameter ))
            {
                id = Convert.ToInt32( filterContext.RouteData.Values[this.RouteParameter] );
            }

            string userName = filterContext.HttpContext.User.Identity.Name;

            return dc.Table<UserTable>().Where( p => p.UserName == userName && p.ParticipantID == id ).Any();
        }

    }

}

이것은 연관 속성의 코드, 즉, 라우팅 매개 변수의 ID와 사용자 테이블의 사용자 ID 사이의 조인 테이블에 연합이 존재합니다. System.linq.dynamic 코드에 대한 종속성이 있습니다. VS2008 샘플.

[AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false )]
public class RoleOrOwnerAssociatedAuthorizationAttribute : MasterEventAuthorizationAttribute
{
    private IDataContextFactory ContextFactory { get; set; }

    public RoleOrOwnerAssociatedAuthorizationAttribute()
        : this( null )
    {
    }

    // this supports unit testing
    public RoleOrOwnerAssociatedAuthorizationAttribute( IDataContextFactory factory )
    {
        this.ContextFactory = factory ?? new DefaultDataContextFactory();
    }

    /// <summary>
    /// The table in which to find the current user by name.
    /// </summary>
    public string UserTable { get; set; }
    /// <summary>
    /// The name of the property in the UserTable that holds the user's name to match against
    /// the current context's user name.
    /// </summary>
    public string UserNameProperty { get; set; }
    /// <summary>
    /// The property to select from the UserTable to match against the UserEntityProperty on the JoinTable
    /// to determine membership.
    /// </summary>
    public string UserSelectionProperty { get; set; }
    /// <summary>
    /// The join table that links users and the entity table.  An entry in this table indicates
    /// an association between the user and the entity.
    /// </summary>
    public string JoinTable { get; set; }
    /// <summary>
    /// The property on the JoinTable used to hold the entity's key.
    /// </summary>
    public string EntityProperty { get; set; }
    /// <summary>
    /// The property on the JoinTable used to hold the user's key.
    /// </summary>
    public string UserEntityProperty { get; set; }
    /// <summary>
    /// The name of the route data parameter which holds the group's key being requested.
    /// </summary>
    public string RouteParameter { get; set; }

    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        using (var dc = this.ContextFactory.GetDataContextWrapper())
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException( "filterContext" );
            }

            if (AuthorizeCore( filterContext.HttpContext ))
            {
                SetCachePolicy( filterContext );
            }
            else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                // auth failed, redirect to login page
                filterContext.Result = new HttpUnauthorizedResult();
            }
            else if (filterContext.HttpContext.User.IsInRole( "SuperUser" )
                     || IsRelated( filterContext, this.GetTable( dc, this.JoinTable ), this.GetTable( dc, this.UserTable ) ))
            {
                SetCachePolicy( filterContext );
            }
            else
            {
                ViewDataDictionary viewData = new ViewDataDictionary();
                viewData.Add( "Message", "You do not have sufficient privileges for this operation." );
                filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData };
            }
        }
    }

    protected bool IsRelated( AuthorizationContext filterContext, IQueryable joinTable, IQueryable userTable )
    {
        bool result = false;
        try
        {
            int entityIdentifier = Convert.ToInt32( filterContext.RouteData.Values[this.RouteParameter] );
            int userIdentifier = this.GetUserIdentifer( filterContext, userTable );

            result = joinTable.Where( this.EntityProperty + "=@0 and " + this.UserEntityProperty + "=@1",
                                      entityIdentifier,
                                      userIdentifier )
                              .Count() > 0;
        }
        catch (NullReferenceException) { }
        catch (ArgumentNullException) { }
        return result;
    }

    private int GetUserIdentifer( AuthorizationContext filterContext, IQueryable userTable )
    {
        string userName = filterContext.HttpContext.User.Identity.Name;

        var query = userTable.Where( this.UserNameProperty + "=@0", userName )
                             .Select( this.UserSelectionProperty );

        int userIdentifer = -1;
        foreach (var value in query)
        {
            userIdentifer = Convert.ToInt32( value );
            break;
        }
        return userIdentifer;
    }

    private IQueryable GetTable( IDataContextWrapper dc, string name )
    {
        IQueryable result = null;
        if (!string.IsNullOrEmpty( name ))
        {
            DataContext context = dc.GetContext<DefaultDataContext>();
            PropertyInfo info = context.GetType().GetProperty( name );
            if (info != null)
            {
                result = info.GetValue( context, null ) as IQueryable;
            }
        }
        return result;
    }
}

다른 팁

나는 매우 물었다 비슷한 질문S#ARP 아키텍처 뉴스 그룹 어느 쪽이든 Tom Cabanski AOP 프레임 워크를 제안했습니다 포스트 쇼트. 이것은 내 필요에 대한 실행 가능한 솔루션처럼 보이므로 더 심도있는 살펴볼 계획입니다. 불행히도, 공유 할 코드 예제가 없기 때문에 이것은 귀하의 질문에 대한 완전한 답변이 아닙니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top