Как я могу разрешить переопределение пользователя с помощью Spring Security? - PullRequest
6 голосов
/ 26 сентября 2011

В моем веб-приложении Spring MVC есть определенные области, доступные только пользователям с достаточными привилегиями. Вместо того, чтобы просто получить сообщение «Отказано в доступе», я должен иметь возможность разрешить пользователям входить в систему как другой пользователь, чтобы использовать эти страницы (что-то вроде переопределения).

Как я могу сделать это с помощью Spring Security?

Вот поток, который я хотел бы получить, с более подробной информацией:

  1. Пользователь A заходит на страницу X из внешнего приложения и аутентифицируется с помощью заголовков
  2. Пользователь A не имеет разрешения на использование страницы X, и поэтому он выводится на экран входа в систему с сообщением о том, что он должен войти в систему как пользователь с достаточными правами доступа для использования этой страницы
  3. Пользователь B входит в систему, имеет достаточные привилегии и переходит на страницу X.

Примечание. Страница X содержит большую и длинную строку запроса, которую необходимо сохранить.

Как я могу сделать это с помощью Spring Security?


Вот мой весенний конфигурационный файл безопасности:

<?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"
    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">

    <debug />

    <global-method-security pre-post-annotations="enabled">
        <!-- AspectJ pointcut expression that locates our "post" method and applies 
            security that way <protect-pointcut expression="execution(* bigbank.*Service.post*(..))" 
            access="ROLE_TELLER"/> -->
    </global-method-security>

    <!-- Allow anyone to get the static resources and the login page by not applying the security filter chain -->
    <http pattern="/resources/**" security="none" />
    <http pattern="/css/**" security="none" />
    <http pattern="/img/**" security="none" />
    <http pattern="/js/**" security="none" />

    <!-- Lock everything down -->
    <http 
        auto-config="true"
        use-expressions="true" 
        disable-url-rewriting="true">

        <!-- Define the URL access rules -->
        <intercept-url pattern="/login" access="permitAll" />
        <intercept-url pattern="/about/**" access="permitAll and !hasRole('blocked')" />
        <intercept-url pattern="/users/**" access="hasRole('user')" />
        <intercept-url pattern="/reviews/new**" access="hasRole('reviewer')" />
        <intercept-url pattern="/**" access="hasRole('user')" />

        <form-login 
            login-page="/login" />

        <logout logout-url="/logout" /> 

        <access-denied-handler error-page="/login?reason=accessDenied"/>

        <!-- Limit the number of sessions a user can have to only 1 -->
        <session-management>
            <concurrency-control max-sessions="1" />
        </session-management>
    </http>

    <authentication-manager>
        <authentication-provider ref="adAuthenticationProvider" />
        <authentication-provider>
            <user-service>
                <user name="superadmin" password="superadminpassword" authorities="user" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

    <beans:bean id="adAuthenticationProvider" class="[REDACTED Package].NestedGroupActiveDirectoryLdapAuthenticationProvider">
        <beans:constructor-arg value="[REDACTED FQDN]" />
        <beans:constructor-arg value="[REDACTED LDAP URL]" />
        <beans:property name="convertSubErrorCodesToExceptions" value="true" />
        <beans:property name="[REDACTED Group Sub-Tree DN]" />
        <beans:property name="userDetailsContextMapper" ref="peerReviewLdapUserDetailsMapper" />
    </beans:bean>

    <beans:bean id="peerReviewLdapUserDetailsMapper" class="[REDACTED Package].PeerReviewLdapUserDetailsMapper">
        <beans:constructor-arg ref="UserDAO" />
    </beans:bean>

</beans:beans>

Я использую слегка модифицированную версию возможностей подключения к Active Directory в Spring Security 3.1. Модификации просто загружают все групп пользователей, включая те, которые достигаются вложением групп, а не только те, в которых пользователь непосредственно входит. Я также использую пользовательский объект пользователя, в который встроен объект пользователя моего приложения, и пользовательский преобразователь LDAP, который выполняет обычное отображение LDAP, а затем добавляет моего пользователя.

Существует специальный сценарий аутентификации, который еще не был реализован, когда аутентификация пользователя осуществляется на основе имени пользователя, переданного из внешнего приложения (или через Kerberos) в режиме единого входа.

Ответы [ 2 ]

2 голосов
/ 27 сентября 2011

Как проверить роли?

Если вы определите их в контексте безопасности следующим образом:

<intercept-url pattern="/adminStuff.html**" access="hasRole('ROLE_ADMIN')" />

Вы можете установить defaultFailureUrl в * 1008.* и когда пользователь с меньшими правами пытается получить доступ к защищенному URL-адресу, FaliureHandler должен перенаправить вас на defaultFailureUrl, который может быть вашей страницей входа в систему.

Вы можете ввести FaliureHandler в фильтр в позиции FORM_LOGIN_FILTER.

<bean id="myFaliureHandler" 
    class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
    <property name="defaultFailureUrl" value="http://yourdomain.com/your-login.html"/>
</bean>

<bean id="myFilter"
   class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
   <property name="authenticationFailureHandler" ref="myFaliureHandler"/>
</bean>    

<http>
  <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
</http>

Ответ 1) в комментарии.

Это будет немного больше работы, чем я думалучитывая вашу конфигурацию пространства имен.

Что вам нужно сделать, это удалить определение <form-login> и вместо него добавить 'custom' UsernamePasswordAuthenticationFilter (это фильтр, который обрабатывает элемент <form-login>).

Вам также нужно удалить <access-denied-handler>.

, чтобы ваша конфигурация выглядела примерно так:

<bean id="myFaliureHandler" 
    class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
    <property name="defaultFailureUrl" value="http://yourdomain.com/your-login.html"/>
</bean>

<bean id="myFilter"
   class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
   <property name="authenticationFailureHandler" ref="myFaliureHandler"/>
   <!-- there are more required properties, but you can read about them in the docs -->
</bean>

<bean id="loginUrlAuthenticationEntryPoint"
   class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
   <property name="loginFormUrl" value="/login"/>
</bean>

<http entry-point-ref="authenticationEntryPoint" auto-config="false">

  <!-- your other http config goes here, just omit the form-login element and the access denied handler -->

  <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
</http>

Как правило, также посмотрите на пружинные документы .на пользовательских фильтрах , если вы еще этого не сделали.В настоящее время мы используем эту конфигурацию в моей текущей компании, заставляя пользователей заново регистрироваться, если у них нет необходимых привилегий на странице.

0 голосов
/ 23 мая 2013

Решение 1

Зарегистрируйте приложение в широком диапазоне ExeptionResolver , используя любое удобное вам значение.Например,

public class MyApplicationErrorResolver extends SimpleMappingExceptionResolver {

    @Autowired
    private List<LogoutHandler> logoutHandlers;

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request,
        HttpServletResponse response, Object handler, Exception ex) {

        if(ex instanceof AccessDeniedException) {
            for(LogoutHandler lh : logoutHandlers) {
                lh.logout(request, response, SecurityContextHolder.getContext().getAuthentication());
            }
            // Not present as a bean. So create it manually.
            SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler();
            logoutHandler.setInvalidateHttpSession(true);
            logoutHandler.logout(request, response, SecurityContextHolder.getContext().getAuthentication());

            return new ModelAndView(new RedirectView(request.getRequestURL().toString()));
        }

        return super.doResolveException(request, response, handler, ex);
    }
}

зарегистрируйте его как компонент:

<bean class="package.path.MyApplicationErrorResolver" />

(это все, что вам нужно, чтобы зарегистрировать его).Это будет работать для вашей конфигурации.Но вам, вероятно, потребуется удалить элемент <access-denied-handler> из конфигурации.

Решение 2

Другой способ - использовать AccessDeniedHandler .Например:

public class MyAccessDeniedExceptionHandler implements AccessDeniedHandler {

    @Autowired
    private List<LogoutHandler> logoutHandlers;

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
        for(LogoutHandler lh : logoutHandlers) {
            lh.logout(request, response, SecurityContextHolder.getContext().getAuthentication());
        }

        SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler();
        logoutHandler.setInvalidateHttpSession(true);
        logoutHandler.logout(request, response, SecurityContextHolder.getContext().getAuthentication());

        response.sendRedirect(request.getRequestURL().toString());
    }

}

зарегистрируйте его как bean-компонент:

<bean id="accesssDeniedHandler" class="package.path.MyAccessDeniedExceptionHandler" />

и укажите его в вашей конфигурации:

<access-denied-handler ref="accesssDeniedHandler" />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...