【问题标题】:Spring Security | Method level security with @Secured/@PreAuthorize春季安全 |使用@Secured/@PreAuthorize 的方法级安全性
【发布时间】:2013-05-01 07:45:46
【问题描述】:

我一直在尝试在我一直在开发的这个应用程序上使用“方法级别”安全性。这个想法是保护使用 DWR 从表示层调用的方法。 现在,我尝试在我的方法中添加以下注释:

@PreAuthorize("isAuthenticated() and hasRole('ROLE_CUSTOMER')")

以及我的安全上下文中的相应条目:

<global-method-security pre-post-annotations="enabled" />

在类似的行中,我尝试了@Secured 注释:

@Secured({"ROLE_CUSTOMER" })

以及我的安全上下文中的相应条目:

<global-method-security secured-annotations="enabled" />

理想情况下,我希望如果用户未通过身份验证,他们应该被重定向到“登录”页面,并且不应该检查“角色”。在这种情况下,即使对于未经身份验证的用户,此方法调用也会导致“AccessDeniedException”。在这种情况下,我需要它来将用户重定向到登录页面。

为了向前推进,我什至尝试通过创建自定义 AccessDenied 处理程序来处理 accessdenied 异常。不幸的是,处理程序从未被调用,但抛出了异常。

这是配置:

<access-denied-handler ref="customAccessDeniedHandler"/>

这在同一文件中定义了相应的处理程序 bean。

仍然没有运气。 accessdeniedhandler 永远不会被调用。

总结一下需求,我需要一个方法。如果此方法被调用,并且用户未经身份验证,则用户应该被重定向到“登录”页面(目前正在抛出 Accessdenied execption)。

感谢您的帮助..

编辑 1:这是来自安全上下文的 sn-p:

<http>
    <intercept-url pattern="/*sign-in.do*" requires-channel="$secure.channel}" />
    .....
    ..... 
    .....
    <intercept-url pattern="/j_acegi_security_check.do" requires-channel="${secure.channel}" />

    <intercept-url pattern="/*.do" requires-channel="http"  />
    <intercept-url pattern="/*.do\?*" requires-channel="http" />
    <form-login login-page="/sign-in.do" authentication-failure-url="/sign-in.do?login_failed=1"
        authentication-success-handler-ref="authenticationSuccessHandler" login-processing-url="/j_acegi_security_check.do"/>

    <logout logout-url="/sign-out.do" logout-success-url="/index.do" />

    <session-management session-authentication-strategy-ref="sessionAuthenticationStrategy" />
        <access-denied-handler ref="customAccessDeniedHandler"/>
  </http>
    <beans:bean id="customAccessDeniedHandler" class="com.mypackage.interceptor.AccessDeniedHandlerApp"/>

【问题讨论】:

    标签: spring security spring-mvc spring-security dwr


    【解决方案1】:

    我对 DWR 不是很熟悉,但我知道它是一种 RPC 机制。问题是客户端javascript发送的RPC请求不是由浏览浏览器的用户发起的常规页面请求。对此类 RPC 请求的响应不可能使浏览器离开当前页面,因为响应是由您的 javascript 代码而不是浏览器处理的。

    你可以做的是:

    1. 实施一种急切的身份验证:在允许用户访问发出 DWR(或任何类型的 RPC)请求的 webapp (URL) 之前,将用户重定向到一个简单的 .jsp 登录页面。
    2. 如果远程过程抛出的AccessDeniedException以某种形式传播到客户端,您可以尝试从javascript代码处理它,例如通过弹出登录对话框,并在AJAX请求中提交用户的凭据. (在这种情况下,请确保保存返回的会话 id,并将其与每个后续请求一起发回。)

    【讨论】:

    • 感谢您的回复 zagyi..我理解这个想法。但是,如果我们完全不考虑 dwr,并假设通过 spring mvc 控制器调用安全方法,即使这样我也会得到 accessdenied 异常,并且不会调用自定义处理程序。您可以在这里建议任何解决方法吗?跨度>
    • 你能分享你的整个安全配置吗?需要它来帮助您解决问题。
    • Zagyi,至于您的第一个建议,进行 dwr 调用的 url 已经是一个受保护的页面。但是,在会话超时的情况下会出现问题。在这种情况下,dwr 调用仍然通过。作为一种解决方法,我创建了一个 dwr ajax 过滤器,它拦截所有 dwr 调用,并可能检查用户是否已登录或具有有效会话。不过,这并不是最好的方法。
    【解决方案2】:

    我有兴趣查看您的 security.xml 文件的其余部分(特别是 &lt;http&gt; 元素),因为如果 每个 用户都被拒绝,这表明您有一个&lt;intercept-url&gt; 覆盖对控制器类的调用的属性。如果没有,添加的信息可能有助于阐明问题。

    假设到目前为止我还很遥远,另一个可能的错误点可能是指定的access-denied-page 本身——如果它的路径是受保护的路径(即&lt;intercept-url&gt;),或者如果它没有被指定,你可能会看到您所说的错误。

    当然,我也对 DWR 不熟悉,所以我有点明显地假设了一个标准的 Spring MVC 框架......

    【讨论】:

    • 您好 cabbagery & zagyi,感谢您的回复。这是安全上下文的剪辑版本。该文件很大,所以我删除了某些部分。如果您需要更多信息,请告诉我。
    • 补充一点,如果我可以让它与调用安全服务方法的 Spring 控制器一起工作,我会很高兴。我现在可以取消 DWR。非常感谢您的时间。
    【解决方案3】:

    好的,我没有成功找到为什么我得到 AccessDeniedException。无论如何,我一直在努力解决它,直到找到原因为止。以下是我采取的几种方法:

    1) 正如 Zagyi 所提到的,我能够将 AccessDenied 异常传播到客户端。我可以创建一个异常处理程序并将用户重定向到登录页面。

    但是,我采用了不同的方法(这可能不是最理想的,但目前似乎可行。这是我所做的:

    1) 创建了一个 DWRAjaxFilter 并仅映射到我感兴趣的远程对象。这将只有对这些远程方法的 DWR 调用被过滤器拦截。这是因为我不希望所有 DWR 公开的方法都用于登录。

       <create creator="spring" javascript="downloadLinksAjaxService">
           <param name="beanName" value="downloadLinksAjaxService" />
           <include method="methodOne" />
           <include method="methodTwo" />  
           <filter class="com.xyz.abc.interceptor.DwrAjaxFilter"></filter>
       </create>
    

    2) 下面是实际的过滤器实现:

    public class DwrSessionFilter implements AjaxFilter {
        public Object doFilter(final Object obj, final Method method,
                final Object[] params, final AjaxFilterChain chain)
                throws Exception {
    
            SecurityContext context = SecurityContextHolder.getContext();
            Authentication auth = context.getAuthentication();
            if (!auth.isAuthenticated()
                    || auth.getAuthorities().contains(
                            new GrantedAuthorityImpl("ROLE_ANONYMOUS"))) {
                throw new LoginRequiredException("Login Required");
            } else {
                return chain.doFilter(obj, method, params);
            }
        }
    }
    

    3) 这是客户端处理程序:

    function errorHandler(message, exception){
    
                    if(exception && exception.javaClassName == "org.directwebremoting.extend.LoginRequiredException") {
    
                      document.location.reload();
                    }
                }
    

    4) 我还为 DWR 添加了异常映射器,以便我可以将 JAVA 异常转换为 JS 异常:

    <convert match="java.lang.Exception" converter="exception">
                <param name='include' value='message'/>
            </convert> 
    

    5) 到目前为止,这似乎运作良好。我仍在测试这个,看看它是否在某个地方失败。

    不胜感激。

    【讨论】:

      猜你喜欢
      • 2013-12-22
      • 2014-02-02
      • 2012-12-13
      • 2017-11-30
      • 2021-05-12
      • 2019-03-31
      • 1970-01-01
      相关资源
      最近更新 更多