如何在 Spring Security 中获取 permitAll 以不在 @Controller 对象中抛出 AuthenticationCredentialsNotFoundException?

Posted

技术标签:

【中文标题】如何在 Spring Security 中获取 permitAll 以不在 @Controller 对象中抛出 AuthenticationCredentialsNotFoundException?【英文标题】:How do I get permitAll in Spring Security to NOT throw AuthenticationCredentialsNotFoundException in @Controller object? 【发布时间】:2011-05-28 02:22:58 【问题描述】:

我有一个控制器,它有很多动作,它指定了一个默认的类级别 @PreAuthorize 注释,但我想让任何人都可以执行其中一个动作(“显示”动作)。

@RequestMapping("/show/pressReleaseId")
@PreAuthorize("permitAll")
public ModelAndView show(@PathVariable long pressReleaseId) 
    ModelAndView modelAndView = new ModelAndView(view("show"));

    modelAndView.addObject("pressRelease",
        sysAdminService.findPressRelease(pressReleaseId));

    return modelAndView;

不幸的是,Spring Security 抛出了这个异常:

org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:321)
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:195)
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64)

如何让 Spring Security 不抛出此异常?我只想让任何人进入 - 未经身份验证的用户和经过身份验证的用户 - 每个人。

我唯一的解决方案是将此方法完全放入另一个控制器中,根本没有@PreAuthorize...这会起作用,但这很愚蠢。我想将所有新闻稿操作保存在同一个控制器中。

感谢您的帮助!

【问题讨论】:

【参考方案1】:

我猜你没有启用匿名身份验证过滤器。

如果你使用命名空间配置和auto-config = "true",它应该默认启用。如果你不使用自动配置,你可以启用匿名过滤为<security:anonymous />

【讨论】:

这是最好的答案 - 在此处查看详细信息docs.spring.io/spring-security/site/docs/current/reference/html/… 这个的java配置是什么?【参考方案2】:

允许任何人访问控制器方法的正常方法是使用任何 Spring Security 注释对其进行注释;即没有@PreAuthorize 没有@Secured 等。

您应该能够简单地从show() 方法中删除@PreAuthorize,任何将注释留在该控制器中的其他方法上。无论您使用 show() 方法做什么,其他方法都将保持安全。

【讨论】:

这真的很糟糕,因为这意味着我必须指定 X 个相同的 @PreAuthorize 注释,而不是指定类级别的默认值,然后对每个控制器操作进行 X 测试以验证我没有忘记将它包含在除 show() 操作之外的所有操作中。这只是弹簧安全方面的糟糕设计。他们应该有一个“doNothing”命令以允许类级别的默认值正常工作:( 鉴于@PreAuthorize注解的内容是一个Spring EL表达式,你能写一个总是返回true的表达式吗?即@PreAuthorize("true")?我还没有尝试过,但这似乎是一种可能的解决方法...... 值得一试;)但是不,不工作。哦,好吧......我有这么多控制器存在安全问题,我认为这对 Spring Security 来说太混乱了,以至于迫使开发人员分别测试每个操作而不使用类级别的默认值。我必须告诉他们解决这个问题,因为这对于大型应用程序来说太糟糕了。 插件版本 2 更改了默认行为。现在一切都默认安全了!【参考方案3】:

默认值随着 Spring 安全插件的更新版本(版本 2)而更改。这意味着默认情况下所有控制器都是安全的(您需要登录才能看到它们)。删除 @Secured 根本不起作用,它仍然会保持安全。您可以更改此默认行为,但对我而言,新的默认行为是有意义的,因为它更安全。而且安全非常重要。

我只用

@Secured(['permitAll'])

适用于我的控制器,但它也应该适用于方法。

【讨论】:

这不是有效的Java,试试@Secured("permitAll")

以上是关于如何在 Spring Security 中获取 permitAll 以不在 @Controller 对象中抛出 AuthenticationCredentialsNotFoundException?的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 Spring Security SessionRegistry?

如何在Grails 2单元测试中获取spring security提供的currentUser

如何使用 Spring Security 在代码中获取用户的授权凭据?

如何在 Spring Security 中测试 AuthenticationPrincipal 并获取 ID 令牌?

如何使用spring security在grails中获取所有当前登录用户的列表(包括rememberme cookie)

如何在 Spring 获取之前捕获 Spring Security 登录表单?