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

发布于 2024-12-12 04:47:40 字数 404 浏览 0 评论 0 原文

例如,我有:

<intercept-url pattern="/aaa/**" access="ROLE_AAA" />
<intercept-url pattern="/bbb/**" access="ROLE_BBB" />

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

并且,如果他试图获取 /bbb并且没有 ROLE_BBB ->到页面/access-denied-bbb/。

目前我只能描述一个AccessDeniedHandler,一个通用的accessDenied页面......

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

For example, I have :

<intercept-url pattern="/aaa/**" access="ROLE_AAA" />
<intercept-url pattern="/bbb/**" access="ROLE_BBB" />

And, accordingly, if user wanted page /aaa and at the same time had no role ROLE_AAA - I want make him redirect to page /access-denied-aaa/

And, if he was trying to get /bbb and had no ROLE_BBB -> to page /access-denied-bbb/.

Currently I can describe only one AccessDeniedHandler, with a one common accessDenied page...

How it is normally can be implemented? preferably using the Spring Security

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

若水微香 2024-12-19 04:47:40

您始终可以实现自己的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 '/'");
        }
    }
}

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

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

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

...
<http auto-config="true">
    <access-denied-handler ref="pbrADH" />
    ...
</http>

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

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

更好的配置方法是这样的:

<property name="errorPagesByRoles">
  <map>
    <entry key="ROLE_AAA" value="/errorpageaaa.jsp" />
    <entry key="ROLE_BBB" value="/errorpagebbb.jsp" />
  </map>
</property>

但我找不到一种方法来知道用户没有的角色是什么导致了错误。如果您查看 RoleVoter 代码,可以看到这条信息丢失了。

You can always implement your own AccessDeniedHandler. Here's an example I made by extending the default AccessDeniedHandlerImpl (package and imports omitted):

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 '/'");
        }
    }
}

Here's how you configure it in your application context configuration file:

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

Don't forget to tell Spring Security to use it, in your http section:

...
<http auto-config="true">
    <access-denied-handler ref="pbrADH" />
    ...
</http>

First of all, remember: this is just an idea. It works, but it can be improved.

Basically it has a Map in which the keys are the protected resources, and the values are their error pages. And it has a default one.
It uses an AntPathMatcher to determine the error page for the current request so you can normally use ant paths. After it decides what is the error page, the class just call the handle method of it's superclass (AccessDeniedHandlerImpl).

A better way to configure it would be something like:

<property name="errorPagesByRoles">
  <map>
    <entry key="ROLE_AAA" value="/errorpageaaa.jsp" />
    <entry key="ROLE_BBB" value="/errorpagebbb.jsp" />
  </map>
</property>

But I couldn't find a way to know what was the role the user didn't had that caused the error. If you look at the RoleVoter code, you can see that this information is lost.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文