尽管已授予权限,Spring Security 仍拒绝访问“@Secured”方法

所以我有一个@Secure为 Spring Security 设计的 Vaadin (8) 视图:


@Secured(SUPERADMIN_ROLE)

@SpringView(name = AdminHomeView.NAME)

class AdminHomeView : DemoViewWithLabel(){

    companion object {

        const val NAME = "admin/home"

    }


    override val labelContent = "This is the protected admin section. You are authenticated and authorized."

}

哪里DemoViewWithLabel只是一个非常简单的抽象类显示


VerticalLayout(Label(labelContent))

因此,如果我以具有该角色的身份登录Superadmin,我就可以很好地访问该视图。


但是,让我们做一个小改动并覆盖一个方法......


@Secured(SUPERADMIN_ROLE)

@SpringView(name = AdminHomeView.NAME)

class AdminHomeView : DemoViewWithLabel(){

    companion object {

        const val NAME = "admin/home"

    }


    override val labelContent = "This is the protected admin section. You are authenticated and authorized."


    override fun enter(event: ViewChangeListener.ViewChangeEvent?) {

        super.enter(event)

    }

}

这让我AccessDeniedException……我不明白为什么。


所以我打开了 Spring Security 的 debug loggign,这就是它必须说的:


Secure object: ReflectiveMethodInvocation: public void ch.cypherk.myapp.ui.views.admin.AdminHomeView.enter(com.vaadin.navigator.ViewChangeListener$ViewChangeEvent);

  target is of class [ch.cypherk.myapp.ui.views.admin.AdminHomeView];

  Attributes: [Superadmin]

Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@a6801701:

  Principal: ch.cypherk.myapp.model.auth.MyUserDetails@6e4c5c5b;

  Credentials: [PROTECTED];

  Authenticated: true; Details: null;

  Granted Authorities: RIGHT_MANAGER, Superadmin 

到目前为止,这似乎还可以。它需要一个Superadmin权限,并且它有一个具有该Superadmin权限的经过身份验证的用户。


森林海
浏览 102回答 1
1回答

梵蒂冈之花

简而言之授予的权限不会显示ROLE_-prefix,因此会被RoleVoter.将 替换为RoleVoter具有空前缀的自定义实现解决了该问题。全文现在这留下了为什么我们可以访问视图的问题。解释很简单,但需要更多的上下文。我们正在努力将 Thorntail 应用程序迁移到 Spring Boot。我们正在使用 Vaadin 8(因为我们有遗留的 Vaadin 7 东西,我们还没有设法摆脱它,需要支持)。所以?Vaadin 是一个单页框架,Vaadin 8 有这种讨厌的视图引用方式,即它使用#!根 url(例如https://<host>:<port>/#!foo/bar/baz/...)。之后什么#都没有发送到服务器,这意味着我们无法区分访问/和访问/#!foo/bar/baz/...因此,我们不能使用 Spring Security 来保护对视图的访问。并且我们有一个 Vaadin 视图,我们需要允许未经身份验证的访问。因此,我们被迫允许对/. (MainUI处理所有传入请求的)将检查用户是否已通过身份验证,如果未通过身份验证,则重定向到登录页面。对视图本身的访问由 Vaadin 保护,而不是 Spring。将SpringViewProvider找不到View用户无权访问的内容(因此,用户无法导航到那里)。但是,只要我们在该视图上调用方法,Spring 安全性就会介入并执行访问检查。正是这些检查失败了,因为授予的权限没有 Spring 预期的“ROLE_”前缀。(我原以为这只是一个约定,但事实并非如此;RoleVoter实际上忽略了不显示前缀的权限,因此您必须那样做,或者您必须提供自己的RoleVoter.)解决方案相对简单......@Configuration@EnableGlobalMethodSecurity(&nbsp; &nbsp; securedEnabled = true,&nbsp; &nbsp; prePostEnabled = true,&nbsp; &nbsp; proxyTargetClass = true)class GlobalSecurityConfiguration : GlobalMethodSecurityConfiguration(){&nbsp; &nbsp; override fun accessDecisionManager(): AccessDecisionManager {&nbsp; &nbsp; &nbsp; &nbsp; return (super.accessDecisionManager() as AffirmativeBased).apply {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; decisionVoters.replaceAll {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; when(it){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; is RoleVoter -> MyRoleVoter()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else -> it&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}在哪里class MyRoleVoter : RoleVoter(){&nbsp; &nbsp; init {&nbsp; &nbsp; &nbsp; &nbsp; rolePrefix = ""&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java