spring security:两个访问被拒绝的页面/处理程序,具体取决于访问的资源

jav*_*irl 2 java spring-security

例如,我有:

<intercept-url pattern="/aaa/**" access="ROLE_AAA" />
<intercept-url pattern="/bbb/**" access="ROLE_BBB" />
Run Code Online (Sandbox Code Playgroud)

因此,如果用户想要页面/ aaa并且同时没有角色ROLE_AAA - 我想让他重定向到page/access-denied-aaa /

并且,如果他试图获得/ bbb且没有ROLE_BBB - > to page/access-denied-bbb /.

目前我只能描述一个AccessDeniedHandler,它有一个常见的accessDenied页面......

通常如何实施?最好使用Spring Security

blu*_*oot 6

你总是可以实现自己的AccessDeniedHandler.这是我通过扩展默认AccessDeniedHandlerImpl(省略包和导入)所做的一个例子:

public class PageByResourceAccessDeniedHandler extends AccessDeniedHandlerImpl {

    //~ Instance fields ===================================

    /**A Map of Path by Error Page*/
    private Map<String, String> errorPagesByPaths;
    /**The default error page if any of {@link #errorPagesByRole} matches */
    private String defaultErrorPage;

    //~ Main Methods ======================================

    @Override
    public void handle(HttpServletRequest request,
            HttpServletResponse response,
            AccessDeniedException accessDeniedException) throws IOException,
            ServletException {
        String errorPage = determineErrorPage(request);
        setErrorPage(errorPage);
        super.handle(request, response, accessDeniedException);
    }

    /**
     * Searches into the property {@link #errorPagesByRole} for a matching error page
     * for the current denied request path.
     * @param request current request
     * @return a matching error page found in {@link #errorPagesByRole} or {@link #defaultErrorPage}
     * if none was found.
     */
    private String determineErrorPage(HttpServletRequest request) {
        AntPathMatcher apm = new AntPathMatcher();

        for (String key : errorPagesByPaths.keySet()) {
            if(apm.match(key, request.getServletPath())) {
                return errorPagesByPaths.get(key);
            }
        }
        return defaultErrorPage;
    }

    //~ Getters/Setters/Utilities =========================

    public void setErrorPagesByPaths(Map<String, String> errorPagesByPaths) {
        for (String key : errorPagesByPaths.keySet()) {
            validateErrorPage(errorPagesByPaths.get(key));
        }
        this.errorPagesByPaths = errorPagesByPaths;
    }

    public void setDefaultErrorPage(String errorPage) {
        validateErrorPage(errorPage);
        this.defaultErrorPage = errorPage;
    }

    /**
     * Simple validator based on {@link AccessDeniedHandlerImpl#setErrorPage(String)}
     * code. Just verifies if the page doesn't starts with <tt>/</tt>.
     * 
     * @throws IllegalArgumentException if the errorPage doesn't starts with <tt>/</tt>.
     */
    private void validateErrorPage(String errorPage) {
        if ((errorPage != null) && !errorPage.startsWith("/")) {
            throw new IllegalArgumentException("errorPage " + errorPage + " must begin with '/'");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是在应用程序上下文配置文件中配置它的方法:

<bean id="pbrADH" class="com.foo.PageByResourceAccessDeniedHandler">
  <property name="defaultErrorPage" value="/errorpagedefault.jsp" />
  <property name="errorPagesByPaths">
    <map>
      <entry key="/aaa/**" value="/errorpageaaa.jsp" />
      <entry key="/bbb/**" value="/errorpagebbb.jsp" />
    </map>
  </property>
</bean>
Run Code Online (Sandbox Code Playgroud)

不要忘记告诉Spring Security在您的http部分中使用它:

...
<http auto-config="true">
    <access-denied-handler ref="pbrADH" />
    ...
</http>
Run Code Online (Sandbox Code Playgroud)

首先,请记住:这只是一个想法.它有效,但可以改进.

基本上它有一个Map,其中键是受保护的资源,值是它们的错误页面.它有一个默认的.
它使用a AntPathMatcher来确定当前请求的错误页面,以便您可以正常使用ant路径.在确定错误页面是什么之后,该类只调用handle它的超类(AccessDeniedHandlerImpl)方法.

配置它的更好方法是:

<property name="errorPagesByRoles">
  <map>
    <entry key="ROLE_AAA" value="/errorpageaaa.jsp" />
    <entry key="ROLE_BBB" value="/errorpagebbb.jsp" />
  </map>
</property>
Run Code Online (Sandbox Code Playgroud)

但我无法找到一种方法来了解用户没有导致错误的角色.如果查看RoleVoter代码,可以看到此信息丢失.