Вопрос

I use Spring security to authenticate users. If a user requests a secured page, he has to authenticate over a login page. If the user is always authenticated, he will be redirected to the requested page immediatly. Moreover some pages need special access rights, and so I setup an access-denied-page temporarily. So far so good.

The scenario: The scenario definies, that the user will get a login-form instead of a static access-denied page, so that a different user can authenticate and if authentication is successful the requested page that needs the higher privileges will open.

The actual spring configuration reads:

<security:http auto-config="true" use-expressions="true" disable-url-rewriting="true">
    <security:intercept-url pattern="/index.jsp" access="permitAll" />
    <security:intercept-url pattern="/loginView" access="permitAll" />
    <security:intercept-url pattern="/accessDenied" access="permitAll"/>
    <security:intercept-url pattern="/user" access="hasRole('ROLE_USER')" />
    <security:intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')" />
    <security:intercept-url pattern="/**" access="denyAll"/>

    <security:form-login login-page="/loginView"
        authentication-failure-url="/loginView"
        default-target-url="/dirView" />

    <security:logout />
    <security:access-denied-handler ref="accessDeniedHandler" />
</security:http>

The accessDeniedHandler-Bean:

public class AccessDeniedServletRequestHandler implements AccessDeniedHandler {

/** {@inheritDoc} */
@Override
public void handle(HttpServletRequest req, HttpServletResponse resp,
        AccessDeniedException accessDeniedException) throws IOException,
        ServletException {

    RequestDispatcher d = req.getRequestDispatcher("/loginView");
    d.forward(req, resp);
}
}

But that implementation of AccessDeniedHandler only forwards to the loginView. After authentication of an admin the default-success-page is openend and not the original requested page. I also tried to save the original request by calling HttpServletRequest#getAttribute("javax.servlet.forward.servlet_path"), but I don't understand how to force spring security to use that original request instead of the default target url.

Besides I read about org.springframework.security.web.savedrequest.SavedRequest that is used inside spring authentication to remember the original request if an unauthenticated user requests a page. But I don't find a valid way how to use the SavedRequest in the same manner for my access denied scenario.

Thanks in advance for suggestions and solutions.

Это было полезно?

Решение

I think your requirements should be satisfied by using the RequestCache API.

If you modify your http configuration you can use the request-cache namespace element:

<security:http>
    ...
    <security:request-cache ref="requestCache"
</security:http>

<bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache" />

You can also inject it into your AccessDeniedHandler. Then all you should need is a simple to saveRequest to setup the cached request which should be restored post-authentication:

public class AccessDeniedServletRequestHandler implements AccessDeniedHandler {
    // Inject this into your class.
    private RequestCache requestCache;

    @Override
    public void handle(HttpServletRequest req, HttpServletResponse resp,
            AccessDeniedException accessDeniedException) throws IOException, ServletException {
        requestCache.saveRequest(req, resp);

        RequestDispatcher d = req.getRequestDispatcher("/loginView");
        d.forward(req, resp);
    }
}

Strictly speaking, you don't actually need to do the bit with the namespace at all, since HttpSessionRequestCache is stateless (it's the internal implementation which is used if you don't override it in the namespace). So you could just create one directly in your AccessDeniedHandler class and it would still work.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top