我有两组 URL - 一组是 REST API,第二组是非常普通的网站。我想为 REST API 应用不同的安全规则,以便偶尔调用 REST API 的用户/脚本将使用 401 代码(基本身份验证很好)或仅 403 来回答。
所以我想允许访问 REST API:
- 已登录的用户(对于调用 REST API 的站点页面上的 javascript,因此共享相同的会话)。
- 一些在 WWW-Authenticate 标头中使用基本身份验证凭据调用 REST API 的脚本。
目前我正试图弄清楚什么配置会让spring“理解”我想要的。我想出了以下配置:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http pattern="/" security="none" />
<http pattern="/static/**" security="none" />
<!-- REST API -->
<http pattern="/rest/*" use-expressions="true">
<http-basic />
<intercept-url pattern="/*" access="isAuthenticated()" />
</http>
<!-- Site -->
<http access-denied-page="/WEB-INF/views/errors/403.jsp" use-expressions="true">
<intercept-url pattern="/index.html" access="hasRole('ROLE_USER') or hasRole('ROLE_ANONYMOUS')" />
<intercept-url pattern="/login.html" access="hasRole('ROLE_USER') or hasRole('ROLE_ANONYMOUS')" />
<intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<form-login login-page="/login.html"
default-target-url="/index.html"
authentication-failure-url="/login.html?error=1" />
<logout logout-url="/logout.do" logout-success-url="/index.html" />
<anonymous username="guest" granted-authority="ROLE_ANONYMOUS" />
<remember-me />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="2" authorities="ROLE_ADMIN,ROLE_USER" />
<user name="alex" password="1" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
不幸的是,不仅基本身份验证不适用于此配置,而且对于匿名用户发出的请求也没有 403 响应 - 应用程序回答重定向 302 Found,我想禁止 REST API url。
我尝试为 REST API 添加自定义入口点:
<beans:bean id="ep403" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
<!-- REST API -->
<http pattern="/rest/*" entry-point-ref="ep403" use-expressions="true">
<intercept-url pattern="/*" access="hasRole('ROLE_USER')" />
<http-basic />
</http>
但这也不起作用。
总结一下我想要得到的东西:
- 允许授权用户访问 REST API(授权工具应考虑 cookie 中的用户会话)。
- 如果脚本指定了正确的身份验证令牌并且未在 cookie 中指定会话,则允许脚本访问 REST API。
更新
在深入研究 Spring Security 内部之后,我发现了决定是否拒绝某些请求的代码。这就是所谓的“访问决策投票者”,基本上它们都适用于某个请求,如果链中的一个访问决策投票者投票拒绝访问某些资源,则该请求最终被拒绝。
因此,最初的问题可以通过引入特殊的访问决策投票器来解决,其行为方式如下:它尝试从会话中提取相关角色(如果请求中存在)并使用该角色继续授权步骤;如果不存在会话,它会尝试根据 WWW-Authenticate 标头中的凭据对用户进行身份验证,然后使用与给定用户关联的角色进行授权步骤。