Spring Security:拒绝访问后,使用管理员用户登录后转发到原始页面

shy*_*ynx 3 authentication spring-security access-denied

我使用Spring安全性对用户进行身份验证。如果用户请求安全页面,则他必须通过登录页面进行身份验证。如果用户始终通过身份验证,则将立即将其重定向到请求的页面。此外,某些页面需要特殊的访问权限,因此我暂时设置了一个访问被拒绝的页面。到目前为止,一切都很好。

方案: 该方案定义为,用户将获得登录表单而不是静态访问拒绝页面,以便其他用户可以进行身份​​验证,并且如果身份验证成功,则将打开需要更高权限的请求页面。

实际的弹簧配置为:

<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>
Run Code Online (Sandbox Code Playgroud)

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);
}
}
Run Code Online (Sandbox Code Playgroud)

但是AccessDeniedHandler的实现仅转发到loginView。在对管理员进行身份验证之后,默认成功页面为openend,而不是原始请求页面。我也尝试通过调用HttpServletRequest#getAttribute(“ javax.servlet.forward.servlet_path”)保存原始请求,但是我不明白如何强制Spring Security使用该原始请求而不是默认目标url。

此外,我还阅读了有关org.springframework.security.web.savedrequest.SavedRequest的信息,如果未经身份验证的用户请求页面,它将在Spring身份验证中用于记住原始请求。但是我找不到一种有效的方法,如何针对拒绝访问的情况以相同的方式使用SavedRequest。

在此先感谢您的建议和解决方案。

Sha*_*eep 5

我认为使用RequestCacheAPI 应该可以满足您的要求。

如果您修改http配置,则可以使用request-cache命名空间元素:

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

<bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache" />
Run Code Online (Sandbox Code Playgroud)

您也可以将其注入您的AccessDeniedHandler。然后,您只需要简单地saveRequest设置缓存的请求,该请求应在身份验证后恢复:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

严格来说,您实际上根本不需要对名称空间做任何事情,因为HttpSessionRequestCache它是无状态的(如果您不在名称空间中覆盖它,则使用内部实现)。因此,您可以直接在您的AccessDeniedHandler班级中创建一个,但仍然可以使用。