Spring 具有重叠配置的安全检查多个 <http> 块中的授权
Spring Security with overlapping configurations checks authorization in multiple <http> blocks
我有一个使用 Spring Security 4.2.18 的应用程序,其安全性在 xml 中配置。现在我在项目中引入 Spring Boot 2.5.4。升级后,我对某些请求的安全配置有问题。
我有一个匹配特定请求的块和一个匹配其余所有请求的块。
<http pattern="/api/**" use-expressions="true" authentication-manager-ref="apiAuthenticationManager" >
<http-basic/>
<intercept-url pattern="/api/**" access="hasRole('ROLE_API')"/>
<csrf disabled="true"/>
</http>
<http pattern="/**" auto-config="true" use-expressions="true" create-session="always" disable-url-rewriting="true"
authentication-manager-ref="authenticationManager">
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/login"
username-parameter="j_username"
password-parameter="j_password"
authentication-failure-url="/login?login_error=t" default-target-url="/redirectlogin"/>
<logout logout-url="/resources/j_spring_security_logout"/>
...
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
...
</http>
<authentication-manager id="apiAuthenticationManager">
<authentication-provider user-service-ref="apiUserDetailsService">
</authentication-provider>
</authentication-manager>
ApiUserDetailsService
遵循规范:
@Service
@Transactional
public class ApiUserDetailsService implements UserDetailsService {
...
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
boolean foundAccount = apiConfig.getUsername().equals(username);
if (foundAccount) {
return new User(username, apiConfig.getPassword(), singletonList(new SimpleGrantedAuthority("ROLE_API")));
}
throw new UsernameNotFoundException("Could not finder user with name " + username);
}
}
如果我在 /api
下发出请求并使用不正确的基本身份验证凭据,我之前会收到 401 未经授权的响应。自升级以来,我被重定向到 /login
并最终进入重定向循环,因为那里也使用了凭据。
如果我删除第二个 <http>
块中的 <intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
,我会得到预期的行为。
如何配置我的应用程序,使我的请求不会尝试使用第二个 <http>
块中的规则进行授权?我曾尝试使用 EntryPoint
,但在使用通用 <http>
块的方法错误地授权用户之前不会调用它。
您是否尝试过将 <intercept-url pattern="/login*" access="permitAll" />
放在 <intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
的正上方,例如:
在第二个 http 块中:
...
<intercept-url pattern="/login*" access="permitAll" />
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
...
问题不在于配置重叠,而是失败的身份验证被重定向到 /login
,后者又由第二个 <http>
配置处理。
我通过创建 AuthenticationEntryPoint
的实现来解决它,它在响应中设置 401 Unathorized
状态:
@Component
public class BasicAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
}
}
然后在我的基本身份验证配置中引用它:
<http pattern="/api/**" use-expressions="true" authentication-manager-ref="apiAuthenticationManager" >
<http-basic entry-point-ref="basicAuthenticationEntryPoint"/>
<intercept-url pattern="/api/**" access="hasRole('ROLE_API')"/>
<csrf disabled="true"/>
</http>
我有一个使用 Spring Security 4.2.18 的应用程序,其安全性在 xml 中配置。现在我在项目中引入 Spring Boot 2.5.4。升级后,我对某些请求的安全配置有问题。
我有一个匹配特定请求的块和一个匹配其余所有请求的块。
<http pattern="/api/**" use-expressions="true" authentication-manager-ref="apiAuthenticationManager" >
<http-basic/>
<intercept-url pattern="/api/**" access="hasRole('ROLE_API')"/>
<csrf disabled="true"/>
</http>
<http pattern="/**" auto-config="true" use-expressions="true" create-session="always" disable-url-rewriting="true"
authentication-manager-ref="authenticationManager">
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/login"
username-parameter="j_username"
password-parameter="j_password"
authentication-failure-url="/login?login_error=t" default-target-url="/redirectlogin"/>
<logout logout-url="/resources/j_spring_security_logout"/>
...
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
...
</http>
<authentication-manager id="apiAuthenticationManager">
<authentication-provider user-service-ref="apiUserDetailsService">
</authentication-provider>
</authentication-manager>
ApiUserDetailsService
遵循规范:
@Service
@Transactional
public class ApiUserDetailsService implements UserDetailsService {
...
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
boolean foundAccount = apiConfig.getUsername().equals(username);
if (foundAccount) {
return new User(username, apiConfig.getPassword(), singletonList(new SimpleGrantedAuthority("ROLE_API")));
}
throw new UsernameNotFoundException("Could not finder user with name " + username);
}
}
如果我在 /api
下发出请求并使用不正确的基本身份验证凭据,我之前会收到 401 未经授权的响应。自升级以来,我被重定向到 /login
并最终进入重定向循环,因为那里也使用了凭据。
如果我删除第二个 <http>
块中的 <intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
,我会得到预期的行为。
如何配置我的应用程序,使我的请求不会尝试使用第二个 <http>
块中的规则进行授权?我曾尝试使用 EntryPoint
,但在使用通用 <http>
块的方法错误地授权用户之前不会调用它。
您是否尝试过将 <intercept-url pattern="/login*" access="permitAll" />
放在 <intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
的正上方,例如:
在第二个 http 块中:
...
<intercept-url pattern="/login*" access="permitAll" />
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
...
问题不在于配置重叠,而是失败的身份验证被重定向到 /login
,后者又由第二个 <http>
配置处理。
我通过创建 AuthenticationEntryPoint
的实现来解决它,它在响应中设置 401 Unathorized
状态:
@Component
public class BasicAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
}
}
然后在我的基本身份验证配置中引用它:
<http pattern="/api/**" use-expressions="true" authentication-manager-ref="apiAuthenticationManager" >
<http-basic entry-point-ref="basicAuthenticationEntryPoint"/>
<intercept-url pattern="/api/**" access="hasRole('ROLE_API')"/>
<csrf disabled="true"/>
</http>