Подтвердить что ты не робот

Создание новых ролей и разрешений Динамически в Spring Безопасность 3

Я использую Spring Security 3 в проекте Struts 2 + Spring IOC.

В моем проекте я использовал Custom Filter, Authentication Provider и т.д.

Вы можете увидеть мой 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 динамически, а не жестко закодированные.

Как создание новых ролей и разрешений и сохранение их в базе данных, а затем доступ к базе данных. Я искал в сети, но я не могу узнать, как добавить новые записи в код.

4b9b3361

Ответ 1

Итак, это по крайней мере два вопроса:

  • Как сделать предоставленные полномочия/привилегии/Роли динамическими?
  • Как сделать ограничение доступа для динамических URL-адресов?

1) Как сделать предоставленные полномочия/привилегии/Роли динамическими?

Я не буду отвечать на это очень подробно, потому что считаю, что эта тема обсуждалась достаточно часто.

Самый простой способ - сохранить полную информацию о пользователе: логин, пароль и роли в базе данных (3 таблицы: пользователь, роли, User2Roles) и использовать JdbcDetailService. Вы можете настроить два выражения SQL (для аутентификации и предоставления ролей) очень хорошо в xml.

Но тогда пользователю нужно выйти и войти в систему, чтобы получить эти новые роли. Если это неприемлемо, вы также должны манипулировать Ролями текущего зарегистрированного пользователя. Они хранятся в сеансе пользователей. Я думаю, что самый простой способ сделать это - добавить фильтр в цепочку фильтров безопасности spring, которая обновляет роли для каждого запроса, если их нужно изменить.

2) Как сделать ограничение доступа для динамических URL?

Здесь у вас есть два способа:

  • Взломав FilterSecurityInterceptor и обновив securityMetadataSource, необходимо сохранить необходимые роли. По крайней мере, вы должны управлять выходом метода DefaultFilterInvocationSecurityMetadataSource#lookupAttributes(String url, String method)
  • Другим способом будет использование других выражений для атрибута access вместо access="hasRole('ROLE_USER')". Пример: access="isAllowdForUserPages1To3". Конечно, вы должны создать этот метод. Это называется "пользовательским обработчиком выражений SpEL" (если у вас есть Spring Security 3 Book вокруг страницы 210. Желание иметь главу номера!). Итак, теперь вам нужно сделать подкласс WebSecurityExpressionRoot и ввести новый метод isAllowdForUserPages1To3. Затем вам нужно подклассом DefaultWebSecurityExpressionHandler и изменить метод createEvaluationContext, чтобы его первый запрос StandartEvaluationContext вызывал супер (вам нужно передать результат в StandartEvaluationContext). Затем замените rootObject на StandartEvaluationContext, используя новую реализацию CustomWebSecurityExpressionRoot. Это тяжелая часть! Затем вам нужно заменить атрибут expressionHanlder expressionVoter (WebExpressionVoter) в конфигурации xml новым подклассом DefaultWebSecurityExpressionHandler. (Это отстой, потому что вам сначала нужно написать много объяснений конфигурации безопасности, поскольку вы не можете получить к ним доступ непосредственно из пространства имен безопасности.)

Ответ 2

Я хотел бы дополнить ответ Ральфа о создании пользовательского выражения SpEL. Его объяснения очень помогли моей попытке найти правильный способ сделать это, но я думаю, что их нужно расширить.

Вот способ создания пользовательского выражения 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 и переопределите метод createSecurityExpressionRoot (аутентификация аутентификации, FilterInvocation fi) (не создайтеEvaluationContext (...)), чтобы вернуть Экземпляр CustomWebSecurityExpressionRoot. Например:

@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 ссылку на ваш обработчик выражения 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

Этот вопрос имеет очень простой ответ. Интересно, почему вы еще не получили свой ответ. Есть две вещи, которые нужно очистить как минимум:

Сначала, вы должны знать, что, когда вы используете пространство имен, автоматически будут добавлены некоторые фильтры для каждого написанного вами URL-адреса.

Второй, вы также должны знать, что делает каждый фильтр. Вернуться к вашему вопросу:
Поскольку вы хотите, чтобы перехват-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".
Поскольку вы хотите иметь все роли и 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);
}
}


вы видите комментарий "Вот ваш код"? Вы должны сами реализовать этот метод.
Я сам имею таблицу с именем URL_ACCESS, которая содержит как URL-адреса, так и их соответствующие роли. После получения URL-адреса от пользователя я просматриваю эту таблицу и возвращаю ее связанную роль.

Поскольку я работаю именно по этому вопросу, вы можете задавать любые вопросы... Я всегда буду отвечать.

Ответ 5

  • Создайте свою модель (пользователь, роль, разрешения) и способ получения разрешений для данного пользователя;
  • Определите свой собственный org.springframework.security.authentication.ProviderManager и configure (установите его поставщиков) на пользовательский org.springframework.security.authentication.AuthenticationProvider; этот последний должен вернуть свой метод аутентификации Аутентификацию, которая должна быть настроена с помощью GrantedAuthority, в вашем случае, все разрешения для данного пользователя.

Уловкой в ​​этой статье является назначение ролей для пользователей, но для установки разрешений для этих ролей в объекте Authentication.authorities.

Для этого я советую вам прочитать API и посмотреть, можно ли расширить основной ProviderManager и AuthenticationProvider вместо того, чтобы все реализовать. Я сделал это, когда LdapAuthenticationProvider установил пользовательский LdapAuthoritiesPopulator, который будет получать правильные роли для пользователя.