복붙노트

[SPRING] 스프링 보안 3에서 새로운 역할과 권한을 동적으로 생성하기 3

SPRING

스프링 보안 3에서 새로운 역할과 권한을 동적으로 생성하기 3

Struts 2 + Spring IOC 프로젝트에서 Spring Security 3을 사용하고 있습니다.

내 프로젝트에서 사용자 지정 필터, 인증 공급자 등을 사용했습니다.

내 security.xml은 여기에서 볼 수 있습니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/security
       http://www.springframework.org/schema/security/spring-security-3.1.xsd">


<global-method-security pre-post-annotations="enabled">
        <expression-handler ref="expressionHandler" />
</global-method-security>

<beans:bean id="expressionHandler"
        class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" >
    <beans:property name="permissionEvaluator" ref="customPermissionEvaluator" />
</beans:bean>

<beans:bean class="code.permission.MyCustomPermissionEvaluator" id="customPermissionEvaluator" />

<!-- User Login -->

  <http auto-config="true" use-expressions="true" pattern="/user/*" >
<intercept-url pattern="/index.jsp" access="permitAll"/>
<intercept-url pattern="/user/showLoginPage.action" access="permitAll"/>
<intercept-url pattern="/user/showFirstPage" access="hasRole('ROLE_USER') or hasRole('ROLE_VISIT')"/>
<intercept-url pattern="/user/showSecondUserPage" access="hasRole('ROLE_USER')"/>
<intercept-url pattern="/user/showThirdUserPage" access="hasRole('ROLE_VISIT')"/>
<intercept-url pattern="/user/showFirstPage" access="hasRole('ROLE_USER') or hasRole('ROLE_VISIT')"/>
<form-login login-page="/user/showLoginPage.action" />
<logout invalidate-session="true"
        logout-success-url="/"
        logout-url="/user/j_spring_security_logout"/>
<access-denied-handler ref="myAccessDeniedHandler" />

  <custom-filter before="FORM_LOGIN_FILTER" ref="myApplicationFilter"/>
  </http>

    <beans:bean id="myAccessDeniedHandler" class="code.security.MyAccessDeniedHandler" />

    <beans:bean id="myApplicationFilter" class="code.security.MyApplicationFilter">
        <beans:property name="authenticationManager" ref="authenticationManager"/>
        <beans:property name="authenticationFailureHandler" ref="failureHandler"/>
        <beans:property name="authenticationSuccessHandler" ref="successHandler"/>
    </beans:bean>

    <beans:bean id="successHandler"
  class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
      <beans:property name="defaultTargetUrl" value="/user/showFirstPage">   </beans:property>
    </beans:bean>

     <beans:bean id="failureHandler"
  class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
      <beans:property name="defaultFailureUrl" value="/user/showLoginPage.action?login_error=1"/>
    </beans:bean>

    <beans:bean id= "myUserDetailServiceImpl" class="code.security.MyUserDetailServiceImpl">
    </beans:bean>

     <beans:bean id="myAuthenticationProvider" class="code.security.MyAuthenticationProvider">
        <beans:property name="userDetailsService" ref="myUserDetailServiceImpl"/>

    </beans:bean>

 <!-- User Login Ends -->

 <!-- Admin Login -->

    <http auto-config="true" use-expressions="true" pattern="/admin/*" >
    <intercept-url pattern="/index.jsp" access="permitAll"/>
    <intercept-url pattern="/admin/showSecondLogin" access="permitAll"/>
    <intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')"/>
    <form-login login-page="/admin/showSecondLogin"/>
    <logout invalidate-session="true"
        logout-success-url="/"
        logout-url="/admin/j_spring_security_logout"/>

    <access-denied-handler ref="myAccessDeniedHandlerForAdmin" />
    <custom-filter before="FORM_LOGIN_FILTER" ref="myApplicationFilterForAdmin"/> 
</http>

<beans:bean id="myAccessDeniedHandlerForAdmin" class="code.security.admin.MyAccessDeniedHandlerForAdmin" />

  <beans:bean id="myApplicationFilterForAdmin" class="code.security.admin.MyApplicationFilterForAdmin">
        <beans:property name="authenticationManager" ref="authenticationManager"/>
        <beans:property name="authenticationFailureHandler" ref="failureHandlerForAdmin"/>
        <beans:property name="authenticationSuccessHandler" ref="successHandlerForAdmin"/>
   </beans:bean>

    <beans:bean id="successHandlerForAdmin"
  class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
    </beans:bean>

    <beans:bean id="failureHandlerForAdmin"
  class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
       <beans:property name="defaultFailureUrl" value="/admin/showSecondLogin?login_error=1"/>
     </beans:bean>

        <authentication-manager alias="authenticationManager">
    <authentication-provider ref="myAuthenticationProviderForAdmin" />
    <authentication-provider ref="myAuthenticationProvider" />
</authentication-manager>

<beans:bean id="myAuthenticationProviderForAdmin" class="code.security.admin.MyAuthenticationProviderForAdmin">
    <beans:property name="userDetailsService" ref="userDetailsServiceForAdmin"/>
</beans:bean>

<beans:bean id= "userDetailsServiceForAdmin" class="code.security.admin.MyUserDetailsServiceForAdminImpl">
</beans:bean>

 <!-- Admin Login Ends -->

<beans:bean id="messageSource"
    class="org.springframework.context.support.ResourceBundleMessageSource">
    <beans:property name="basenames">
        <beans:list>
            <beans:value>code/security/SecurityMessages</beans:value>
        </beans:list>
    </beans:property>            
</beans:bean>

이제 Uptill을 볼 수 있습니다. 언급 한 URL 패턴은 하드 코딩되어 있습니다. 나는 새로운 ROLES와 PERMISSIONS를 동적으로 만들지, 하드 코딩하지 않는지 알고 싶다.

새로운 역할 및 권한을 생성하고 데이터베이스에 저장 한 다음 데이터베이스에서 액세스하는 것과 같습니다. 그물을 검색했지만 코드에 새 항목을 추가하는 방법을 찾을 수 없습니다.

해결법

  1. ==============================

    1.그래서 이것들은 최소한 두 가지 질문이 있습니다 :

    그래서 이것들은 최소한 두 가지 질문이 있습니다 :

    나는이 주제가 충분히 자주 논의되었다고 생각하기 때문에 이것을 아주 자세하게 대답하지 않을 것이다.

    가장 쉬운 방법은 전체 사용자 정보 (로그인, 암호 및 역할)를 데이터베이스 (3 테이블 : 사용자, 역할, User2Roles)에 저장하고 JdbcDetailService를 사용하는 것입니다. XML 구성에서 두 SQL 문 (인증 및 역할 부여 용)을 매우 잘 구성 할 수 있습니다.

    그러나 사용자는이 새로운 역할을 얻기 위해 로그 아웃하고 로그인해야합니다. 허용되지 않는 경우 현재 로그인 한 사용자의 역할도 조작해야합니다. 이들은 사용자 세션에 저장됩니다. 가장 쉬운 방법은 변경해야하는 경우 모든 요청에 ​​대한 역할을 업데이트하는 스프링 보안 필터 체인에 필터를 추가하는 것입니다.

    여기에 마지막으로 두 가지 방법이 있습니다.

  2. ==============================

    2.커스텀 SpEL 표현을 만드는 것에 대한 Ralph의 답변을 보충하고 싶습니다. 그의 설명은 이것을하기위한 올바른 방법을 찾으려는 나의 시도에 많은 도움이되었지만, 나는 그것들을 확장해야한다고 생각한다.

    커스텀 SpEL 표현을 만드는 것에 대한 Ralph의 답변을 보충하고 싶습니다. 그의 설명은 이것을하기위한 올바른 방법을 찾으려는 나의 시도에 많은 도움이되었지만, 나는 그것들을 확장해야한다고 생각한다.

    커스텀 SpEL 표현식을 생성하는 방법은 다음과 같습니다 :

    1) WebSecurityExpressionRoot 클래스의 사용자 정의 서브 클래스를 작성하십시오. 이 서브 클래스에서 표현식에 사용할 새로운 메소드를 작성하십시오. 예 :

    public class CustomWebSecurityExpressionRoot extends WebSecurityExpressionRoot {
    
        public CustomWebSecurityExpressionRoot(Authentication a, FilterInvocation fi) {
            super(a, fi);
        }
    
        public boolean yourCustomMethod() {
            boolean calculatedValue = ...;
    
            return calculatedValue;
    
        }
    }

    2) DefaultWebSecurityExpressionHandler 클래스의 사용자 정의 하위 클래스를 작성하고 CustomWebSecurityExpressionRoot 인스턴스를 리턴하기 위해 메소드 createSecurityExpressionRoot (인증 인증, FilterInvocation fi) (createEvaluationContext (...) 아님)를 대체하십시오. 예 :

    @Component(value="customExpressionHandler")
    public class CustomWebSecurityExpressionHandler extends DefaultWebSecurityExpressionHandler {
    
        @Override
        protected SecurityExpressionRoot createSecurityExpressionRoot(
                Authentication authentication, FilterInvocation fi) {
    
            WebSecurityExpressionRoot expressionRoot = new CustomWebSecurityExpressionRoot(authentication, fi);
    
            return expressionRoot;
    }}

    3) spring-security.xml에 Expression Handler Bean에 대한 참조를 정의한다.

    <security:http access-denied-page="/error403.jsp" use-expressions="true" auto-config="false">
        ...
    
        <security:expression-handler ref="customExpressionHandler"/>
    </security:http>
    

    이 후 표준 사용자 정의 식 대신 사용자 지정 식을 사용할 수 있습니다.

    <security:authorize access="yourCustomMethod()">
    
  3. ==============================

    3.Voter를 사용하여 액세스를 동적으로 제한 할 수 있습니다. Get Spring Security의 데이터베이스 또는 속성으로부터의 URL 수신도 참조하십시오.

    Voter를 사용하여 액세스를 동적으로 제한 할 수 있습니다. Get Spring Security의 데이터베이스 또는 속성으로부터의 URL 수신도 참조하십시오.

  4. ==============================

    4.이 질문은 매우 솔직한 대답입니다. 왜 당신은 아직 당신의 대답을 가지고 있지 않은지 궁금합니다. 최소한 정리해야 할 두 가지가 있습니다. 먼저 네임 스페이스를 사용할 때 작성한 각 URL에 자동으로 일부 필터가 추가된다는 것을 알아야합니다. 둘째, 각 필터가하는 일도 알고 있어야합니다. 질문으로 돌아 가기 : intercept-url을 동적으로 구성하려면 해당 네임 스페이스를 제거한 후 다음 필터로 바꿔야합니다.

    이 질문은 매우 솔직한 대답입니다. 왜 당신은 아직 당신의 대답을 가지고 있지 않은지 궁금합니다. 최소한 정리해야 할 두 가지가 있습니다. 먼저 네임 스페이스를 사용할 때 작성한 각 URL에 자동으로 일부 필터가 추가된다는 것을 알아야합니다. 둘째, 각 필터가하는 일도 알고 있어야합니다. 질문으로 돌아 가기 : intercept-url을 동적으로 구성하려면 해당 네임 스페이스를 제거한 후 다음 필터로 바꿔야합니다.

    <bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
        <sec:filter-chain-map path-type="ant">
            <sec:filter-chain pattern="/css/**" filters="none" />
            <sec:filter-chain pattern="/images/**" filters="none" />
            <sec:filter-chain pattern="/login.jsp*" filters="none" />
            <sec:filter-chain pattern="/user/showLoginPage.action" filters="none" />
            <sec:filter-chain pattern="/**"
                filters="
            securityContextPersistenceFilter,
            logoutFilter,
            authenticationProcessingFilter,
            exceptionTranslationFilter,
            filterSecurityInterceptor" />
        </sec:filter-chain-map>
    </bean>
    

    그런 다음 자신의 SecurityMetadaSource를 FilterSecurityInterceptor에 삽입해야합니다. 다음을 참조하십시오.

    <bean id="filterSecurityInterceptor"
        class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="accessDecisionManager" ref="accessDecisionManager" />
        <property name="securityMetadataSource" ref="myFilterInvocationSecurityMetadataSource" />
    </bean>
    
    <bean id="myFilterInvocationSecurityMetadataSource" class="myPackage.MyFilterSecurityMetadataSource">
    </bean>
    

    그러나 그 전에 먼저 'MyFilterSecurityMetadataSource'를 사용자 정의해야합니다. 이 클래스는 'DefaultFilterInvocationSecurityMetadataSource'를 구현해야합니다. DB에 모든 역할과 URL을 갖고 싶으면 getAttributes를 사용자 정의해야합니다. 이제 다음 구현 예제를 참조하십시오.

    public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    
    
        public List<ConfigAttribute> getAttributes(Object object) {
            FilterInvocation fi = (FilterInvocation) object;
            String url = fi.getRequestUrl();
            List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();
    
            attributes = getAttributesByURL(url); //Here Goes Code
    
            return attributes;
        }
    
        public Collection<ConfigAttribute> getAllConfigAttributes() {
            return null;
        }
    
        public boolean supports(Class<?> clazz) {
            return FilterInvocation.class.isAssignableFrom(clazz);
        }
    }
    

    "Here go your code"코멘트를 보시겠습니까? 당신은 직접 그 방법을 구현해야합니다. 저 자신은 URL과 해당 역할을 모두 포함하는 URL_ACCESS라는 테이블을 가지고 있습니다. 사용자로부터 URL을받은 후 해당 테이블을 조회하고 관련 역할을 반환합니다. 내가이 주제에 대해 정확히 일하고 있기 때문에 어떤 질문을 할 수도 있습니다 ... 나는 항상 대답 할 것입니다.

  5. ==============================

    5.이 기사의 트릭은 사용자에게 역할을 할당하는 것이지만 Authentication.authorities 객체에서 역할에 대한 권한을 설정하는 것입니다.

    이 기사의 트릭은 사용자에게 역할을 할당하는 것이지만 Authentication.authorities 객체에서 역할에 대한 권한을 설정하는 것입니다.

    이를 위해 API를 읽고 모든 것을 구현하는 대신 기본 ProviderManager 및 AuthenticationProvider를 확장 할 수 있는지 확인하는 것이 좋습니다. LdapAuthenticationProvider를 사용하여 사용자의 올바른 역할을 검색하는 사용자 지정 LdapAuthoritiesPopulator를 설정하면됩니다.

  6. from https://stackoverflow.com/questions/8321696/creating-new-roles-and-permissions-dynamically-in-spring-security-3 by cc-by-sa and MIT license