intercept-url
在 Spring 安全性中的元素中制作模式的首选方法是什么?我正在创建一个 Web 服务 (RESTful),我目前要求所有用户都已登录并具有角色ROLE_USER
。@PreAuthorize
然后通过服务层上的注释来实施进一步的约束。intercept-url
但是,添加多个具有不同配置的元素是否很常见?
6 回答
我应该认为“首选方式”是[必然]主观的。我的 . 中有<intercept-url>
元素security.xml
,但放弃了它们,转而使用控制器上的@RequestMapping
注释。@PreAuthorize
这纯粹是个人偏好(在我的情况下),因为我更喜欢将内容保存在 Java 中而不是 XML 命名空间中,尽可能多地这样做。
您可以使用其中一个、另一个或两者,并且可以使注释增强 XML —— 例如,您可以具有以下内容:
安全.xml:
<intercept-url pattern="/something" access="hasRole('ROLE_USER')"/>
你的控制器.java:
@RequestMapping(value="/something/else")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String getSomethingElseContents(){ return "somethingelse"; }
正如我所说,这似乎只是一个偏好问题。使用 XML 命名空间的好处是基本访问规则都在一个地方,易于阅读和遵循。由(或其他注释变体)强加的规则@PreAuthorize
特别有吸引力,因为您可以在其中调用自己的 SpEL 表达式,并根据对传递的参数或类(即@PreAuthorize("@my.project.package.hasMagicPower(#power.INVISIBILITY)")
)可访问的字段或这些的组合的访问权限决定作出许可。您可以将原本不可用的逻辑和动态权限应用于命名空间选项。
当然,您可以使用“和”、“或”和“!”来应用基本逻辑。命名空间中 SpEL 表达式中的连接词(并且您可以通过 XML 中的指示符访问外部类 [boolean] 方法@
),但 XML 中指定的所有内容都必须是静态的。
tl;dr:个人偏好是偏好,但如果您想要或需要权限处理的动态灵活性,则必须使用注释。如果您既不想也不需要动态灵活性,那么您可以选择(并且一个合理的论点会建议命名空间选项相对于 SoC 更好)。我更喜欢让 Java 来处理它的灵活性,因为一旦我设置了我的 XML,我想不管它并专注于 Java。此外,对 SoC 观点有一个有点令人信服的反驳,即适当常规化的 Java 应用程序将其控制器放在易于查找的包中,并具有明显的名称控制。
仍然tl;博士:嗯。六个一个,六个另一个。我说po-tay-to。
大多数使用 Spring Security 的 Web 应用程序只有几个intercept-url
s,因为它们只有非常基本的安全要求。您需要未经身份验证访问登录和登录错误屏幕,通常是公共站点的某些方面,因此可以是一些 URL 模式。然后通常有一个管理部分,然后其他一切都是ROLE_USER
.
如果您需要更多角色,通常会将它们与顶级 URL 路径组件相关联。虽然这不是必需的,但它可以更轻松地确保资源得到适当的保护。
<http realm="Contacts Realm" use-expressions="false">
<intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/admin/*" access="ROLE_ADMIN"/>
<intercept-url pattern="/secret/*" access="ROLE_SECRET"/>
<intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN,ROLE_SECRET"/>
<http-basic/>
</http>
您必须根据您的用例决定是否允许人们拥有多个角色。在应用程序中管理有点困难,因此大多数具有简单安全性的人都会对其进行设置,以便用户只有一个角色,然后他们允许多个角色访问受保护的内容。当然,另一种方法是每个 URL 模式一个角色,并赋予人们多个角色。
无论如何,您的问题(或至少我认为您要问的问题)的答案是,通常要做的事情是每个角色使用一个顶级路径组件来保护具有相同安全限制的所有资源。当然,您也在该路径前缀下对功能进行分组,因此有些人讨厌这种结构,而有些人只是喜欢在代码中使用注释。我喜欢我的安全性,我可以在一个地方看到它,并且可以通过查看 URL 轻松判断安全性期望是什么。
SpringSecurity 的配置取决于您为应用程序选择的身份验证:例如,对于表单身份验证,您要配置登录 url 和注销成功 url 没有权限:
<http realm="Contacts Realm">
<intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/**" access="ROLE_USER"/>
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1"/>
<logout logout-success-url="/index.jsp"/>
</http>
在基本身份验证的情况下,您没有登录和注销 URL,并且配置更简单:
<http realm="Contacts Realm">
<intercept-url pattern="/**" access="ROLE_USER"/>
<http-basic/>
</http>
如果您将选择基本身份验证,请使用第二个示例。
可以通过这种方式拦截 URL。假设您的休息服务 URL 以/rest/
.
<http auto-config="true" use-expressions="true" access-denied-page="/accessDeniedPageURL">
<intercept-url pattern="/rest/**" access="hasRole('ROLE_USER')"/>
<intercept-url pattern="/view/products" access="isFullyAuthenticated()"/>
<form-login login-page="/landing" default-target-url="/view/products" authentication-failure-handler-ref="authenticationFailureHandler"/>
<logout invalidate-session="true" logout-success-url="/landing" delete-cookies="JSESSIONID"/>
<session-management invalid-session-url="/landing" session-authentication-error-url="/landing?msg=alreadyLogin">
<concurrency-control max-sessions="1" expired-url="/landing?msg=sessionExpiredDuplicateLogin" error-if-maximum-exceeded="false"/>
</session-management>
</http>
是的,定义多个拦截 URL 模式然后在顶部添加注释以进一步限制特定资源是很常见的。
您还可以为每个限制使用一个目录,这样您就不需要注释。前任。/user/** 需要 ROLE_USER,/admin/** 需要 ROLE_ADMIN 等。
请记住,在使用任何一种方法时,如果您犯了错误,它会如何影响您的安全。
如果使用拦截 url,则必须按正确的顺序排列行,例如:
<intercept-url pattern="/**" access="permitAll"/>
<intercept-url pattern="/user/**" access="hasRole('ROLE_USER')"/>
行不通,因为您在第一行屏蔽了所有访问权限,因此必须颠倒这些行。如果初学者正在处理您的项目并反转线条,这可能是一个大问题。
如果你使用注解,你可能会误删注解行,在你的应用程序中留下一个安全漏洞。
@PreAuthorize("hasRole('ROLE_USER')")
如果您在两个项目之间重用一个控制器类,并且在一个项目中您希望允许 ROLE_USER 访问控制器内的所有方法,而另一个使用公共代码的项目需要 ROLE_ADMIN,那么实现这一目标的最简单方法是使用拦截网址。
所以请记住,@PreAuthorize 将被硬编码并在项目之间共享。您可以扩展类并为每个项目添加不同的@PreAuthorize,但这会增加额外的复杂性。
我喜欢使用intercept-url 来保护整个区域,例如/user/**,因为错误地删除注释的风险较小。
如果我需要添加细粒度访问,我会在控制器中的方法中添加一个注释,该方法已经由拦截 URL 保护,但这种情况很少发生。
Spring Security 通常适用于基于角色的访问。就是这样。您可以创建自己的 ProcessingFilter 来做一些额外的事情。但是,我发现这对小好处来说是很多工作。
另一种方法是使用请求拦截器。在几个使用 Spring MVC 的 RESTful 服务项目中,我利用请求拦截器来完成基本角色访问之外的一些身份验证。这行得通,在我看来,这使得事件链更容易跟踪,但如果你每分钟处理数千笔交易,它可能会使请求陷入困境。