在 SecurityContext 中找不到身份验证对象 - Spring 5
An Authentication object was not found in the SecurityContext - Spring 5
我是 Spring Boot 和 Spring Security 的新手,并且继承了一个使用它们的 webapp 项目。我们将把 webapp 迁移到新的部署环境。我们将要改变的事情之一是身份验证机制,以便它可以在新环境中运行。同时,我想使用一些现有的 PostMan 测试来测试 REST 端点,绕过安全性。基本上,我想暂时禁用安全性。
我有一个 class 提供全局方法级别的安全性:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
// ...
}
我有多个控制器 class,例如,一个 class 提供有关用户的信息:
@RestController
public class UserController {
@ApiOperation(value = "Gets the list of users for an admin.")
@PreAuthorize("#oauth2.hasScope('dashboard') and #oauth2.hasScope('read') and hasRole('ROLE_SYSADMIN')")
@GetMapping(value = "/user/list", produces = MediaType.APPLICATION_JSON_VALUE)
@AuditAccess(message = "Accessing /user/list")
public ResponseEntity<List<UserResponse>> getUserList() {
// ...
}
// ...
}
如果我尝试 运行 我的 PostMan 测试,它们会失败,因为在我的本地测试环境中没有设置身份验证机制。我绕过安全性的第一次尝试是注释掉 @EnableGlobalMethodSecurity
行,但这导致了 运行 时间错误,大概是由于方法上的 @PreAuthorize
注释。如果我也注释掉那些,我可以得到 运行 的测试。但是,有许多这样的注释分布在许多文件中。我宁愿不评论所有这些;我宁愿暂时替代方法安全性的“什么都不做”版本。这是我的尝试:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
/**
* This class is designed to let everything pass the method filter, i.e.,
* effectively removing method level security.
*/
class DoNothingMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
public Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx) {
return filterTarget;
}
@Override
public void setReturnObject(Object returnObject, EvaluationContext ctx) {
// do nothing
}
}
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
MethodSecurityExpressionHandler doNothingHandler =
new DoNothingMethodSecurityExpressionHandler();
return doNothingHandler;
// TODO restore below
// return new OAuth2MethodSecurityExpressionHandler();
}
}
如果我尝试 运行 我的 PostMan 测试
GET http://localhost:8080/myapp/user/list
我得到一个错误:
2021-12-21 06:28:14,252 INFO [stdout] (default task-1) Request: http://localhost:8080/myapp/user/list }raised
2021-12-21 06:28:14,253 INFO [stdout] (default task-1) org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
2021-12-21 06:28:14,254 INFO [stdout] (default task-1) at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:379) ~[spring-security-core-5.3.1.RELEASE.jar:5.3.1.RELEASE]
2021-12-21 06:28:14,254 INFO [stdout] (default task-1) at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:223) ~[spring-security-core-5.3.1.RELEASE.jar:5.3.1.RELEASE]
2021-12-21 06:28:14,254 INFO [stdout] (default task-1) at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:65) ~[spring-security-core-5.3.1.RELEASE.jar:5.3.1.RELEASE]
2021-12-21 06:28:14,255 INFO [stdout] (default task-1) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,255 INFO [stdout] (default task-1) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,256 INFO [stdout] (default task-1) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,257 INFO [stdout] (default task-1) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,257 INFO [stdout] (default task-1) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,257 INFO [stdout] (default task-1) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,258 INFO [stdout] (default task-1) at mycompany.rest.controller.UserController$$EnhancerBySpringCGLIB$$f2b6b566.getUserList(<generated>) ~[classes:?]
2021-12-21 06:28:14,259 INFO [stdout] (default task-1) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_271]
2021-12-21 06:28:14,259 INFO [stdout] (default task-1) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_271]
2021-12-21 06:28:14,260 INFO [stdout] (default task-1) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_271]
2021-12-21 06:28:14,260 INFO [stdout] (default task-1) at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_271]
2021-12-21 06:28:14,260 INFO [stdout] (default task-1) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,261 INFO [stdout] (default task-1) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,261 INFO [stdout] (default task-1) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,263 INFO [stdout] (default task-1) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,264 INFO [stdout] (default task-1) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,265 INFO [stdout] (default task-1) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,265 INFO [stdout] (default task-1) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,266 INFO [stdout] (default task-1) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
出于某种原因,我们仍在尝试进行身份验证。
此问题与其他一些问题 (, Spring Oauth2 : Authentication Object was not found in the SecurityContext, and An Authentication object was not found in the SecurityContext - Spring 3.2.2) 类似,但涉及不同的版本和不同的用例。我一直无法弄清楚如何将这些答案应用于我的情况。我的 Spring 环境包括:
<spring.version>5.2.5.RELEASE</spring.version>
<spring.oath2.version>2.4.1.RELEASE</spring.oath2.version>
<spring.boot.version>2.2.6.RELEASE</spring.boot.version>
<spring.jwt.version>1.1.0.RELEASE</spring.jwt.version>
<spring.security.version>5.3.1.RELEASE</spring.security.version>
绕过安全机制的简单方法是什么?
您可以尝试设置 prePostEnabled = false,然后删除 WebSecurityConfigurerAdapter 实现中的任何身份验证过滤器,例如
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable().authorizeRequests()
.anyRequest().permitAll();
}
而不是删除 @EnableGlobalMethodSecurity
,您可以保留它但只是禁用它 prePostEnabled
.
但它需要至少启用以下一项(详见this):
- prePostEnabled(启用
@PreAuthorize
/ @PreFilter
/ @PostAuthorize
/ @PostFilter
)
- securedEnabled(启用
@Secured
)
- jsr250Enabled(用于启用 JSR-250 注释,例如
@DenyAll
、 @PermitAll
、 @RolesAllowed
)
- 自定义一个
MethodSecurityMetadataSource
由于您只在现有配置中启用 prePostEnabled
,我相信您现在不应在任何方法上使用任何 @Secured
和 JSR-250 注释。
所以下面的技巧应该只禁用 @PreAuthorize
,同时保持其他东西不变:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = false, securedEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
或
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = false, jsr250Enabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
测试的“切换”代码 (un-/commenting) 是不行的!
(在“严格的团队”中,您甚至可能不会提交注释代码!-> sonarqube)
在复杂(分布式)环境中,具有 (spring) @Profile("test")
(例如关闭安全性)听起来绝对合法!
(单元+集成)测试您的安全性(+配置)仍然是[非常好-必不可少]!
Spring Security 5.5.x Reference Documentation, Chapter 19 Testing
This section describes the testing support provided by Spring Security.
19.1. Testing Method Security
Before we can use Spring Security Test support, we must perform some setup. An example can be seen below:
@RunWith(SpringJUnit4ClassRunner.class) // 1.
@ContextConfiguration // 2.
public class WithMockUserTests { ...
(我们可以将两者合而为一:@SpringBootTest
;)
This is a basic example of how to setup Spring Security Test. The highlights are:
@RunWith
instructs the spring-test module that it should create an ApplicationContext. This is no different than using the existing Spring Test support. For additional information, refer to the Spring Reference
@ContextConfiguration
instructs the spring-test the configuration to use to create the ApplicationContext. Since no configuration is specified, the default configuration locations will be tried. This is no different than using the existing Spring Test support. For additional information, refer to the Spring Reference
Spring Security hooks into Spring Test support using the WithSecurityContextTestExecutionListener
which will ensure our tests are ran with the correct user. It does this by populating the SecurityContextHolder
prior to running our tests. If you are using reactive method security, you will also need ReactorContextTestExecutionListener
which populates ReactiveSecurityContextHolder
. After the test is done, it will clear out the SecurityContextHolder
. If you only need Spring Security related support, you can replace @ContextConfiguration
with @SecurityTestExecutionListeners
.
请记住,我们向 HelloMessageService
添加了 @PreAuthorize
注释,因此它需要经过身份验证的用户才能调用它。如果我们 运行 下面的测试,我们期望下面的测试会通过:
@Test(expected = AuthenticationCredentialsNotFoundException.class)
public void getMessageUnauthenticated() {
messageService.getMessage();
}
(测试预期(身份验证)异常!),所以其中之一:
19.1.2. @WithMockUser
...
19.1.3. @WithAnonymousUser
...
19.1.4. @WithUserDetails
...
19.1.5. @WithSecurityContext
...
19.1.6. Test Meta Annotations
...以及 chapter/reference 的其余部分将很有用。
我是 Spring Boot 和 Spring Security 的新手,并且继承了一个使用它们的 webapp 项目。我们将把 webapp 迁移到新的部署环境。我们将要改变的事情之一是身份验证机制,以便它可以在新环境中运行。同时,我想使用一些现有的 PostMan 测试来测试 REST 端点,绕过安全性。基本上,我想暂时禁用安全性。
我有一个 class 提供全局方法级别的安全性:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
// ...
}
我有多个控制器 class,例如,一个 class 提供有关用户的信息:
@RestController
public class UserController {
@ApiOperation(value = "Gets the list of users for an admin.")
@PreAuthorize("#oauth2.hasScope('dashboard') and #oauth2.hasScope('read') and hasRole('ROLE_SYSADMIN')")
@GetMapping(value = "/user/list", produces = MediaType.APPLICATION_JSON_VALUE)
@AuditAccess(message = "Accessing /user/list")
public ResponseEntity<List<UserResponse>> getUserList() {
// ...
}
// ...
}
如果我尝试 运行 我的 PostMan 测试,它们会失败,因为在我的本地测试环境中没有设置身份验证机制。我绕过安全性的第一次尝试是注释掉 @EnableGlobalMethodSecurity
行,但这导致了 运行 时间错误,大概是由于方法上的 @PreAuthorize
注释。如果我也注释掉那些,我可以得到 运行 的测试。但是,有许多这样的注释分布在许多文件中。我宁愿不评论所有这些;我宁愿暂时替代方法安全性的“什么都不做”版本。这是我的尝试:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
/**
* This class is designed to let everything pass the method filter, i.e.,
* effectively removing method level security.
*/
class DoNothingMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
public Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx) {
return filterTarget;
}
@Override
public void setReturnObject(Object returnObject, EvaluationContext ctx) {
// do nothing
}
}
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
MethodSecurityExpressionHandler doNothingHandler =
new DoNothingMethodSecurityExpressionHandler();
return doNothingHandler;
// TODO restore below
// return new OAuth2MethodSecurityExpressionHandler();
}
}
如果我尝试 运行 我的 PostMan 测试
GET http://localhost:8080/myapp/user/list
我得到一个错误:
2021-12-21 06:28:14,252 INFO [stdout] (default task-1) Request: http://localhost:8080/myapp/user/list }raised
2021-12-21 06:28:14,253 INFO [stdout] (default task-1) org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
2021-12-21 06:28:14,254 INFO [stdout] (default task-1) at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:379) ~[spring-security-core-5.3.1.RELEASE.jar:5.3.1.RELEASE]
2021-12-21 06:28:14,254 INFO [stdout] (default task-1) at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:223) ~[spring-security-core-5.3.1.RELEASE.jar:5.3.1.RELEASE]
2021-12-21 06:28:14,254 INFO [stdout] (default task-1) at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:65) ~[spring-security-core-5.3.1.RELEASE.jar:5.3.1.RELEASE]
2021-12-21 06:28:14,255 INFO [stdout] (default task-1) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,255 INFO [stdout] (default task-1) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,256 INFO [stdout] (default task-1) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,257 INFO [stdout] (default task-1) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,257 INFO [stdout] (default task-1) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,257 INFO [stdout] (default task-1) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,258 INFO [stdout] (default task-1) at mycompany.rest.controller.UserController$$EnhancerBySpringCGLIB$$f2b6b566.getUserList(<generated>) ~[classes:?]
2021-12-21 06:28:14,259 INFO [stdout] (default task-1) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_271]
2021-12-21 06:28:14,259 INFO [stdout] (default task-1) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_271]
2021-12-21 06:28:14,260 INFO [stdout] (default task-1) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_271]
2021-12-21 06:28:14,260 INFO [stdout] (default task-1) at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_271]
2021-12-21 06:28:14,260 INFO [stdout] (default task-1) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,261 INFO [stdout] (default task-1) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,261 INFO [stdout] (default task-1) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,263 INFO [stdout] (default task-1) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,264 INFO [stdout] (default task-1) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,265 INFO [stdout] (default task-1) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,265 INFO [stdout] (default task-1) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
2021-12-21 06:28:14,266 INFO [stdout] (default task-1) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.5.RELEASE.jar:5.2.5.RELEASE]
出于某种原因,我们仍在尝试进行身份验证。
此问题与其他一些问题 (
<spring.version>5.2.5.RELEASE</spring.version>
<spring.oath2.version>2.4.1.RELEASE</spring.oath2.version>
<spring.boot.version>2.2.6.RELEASE</spring.boot.version>
<spring.jwt.version>1.1.0.RELEASE</spring.jwt.version>
<spring.security.version>5.3.1.RELEASE</spring.security.version>
绕过安全机制的简单方法是什么?
您可以尝试设置 prePostEnabled = false,然后删除 WebSecurityConfigurerAdapter 实现中的任何身份验证过滤器,例如
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable().authorizeRequests()
.anyRequest().permitAll();
}
而不是删除 @EnableGlobalMethodSecurity
,您可以保留它但只是禁用它 prePostEnabled
.
但它需要至少启用以下一项(详见this):
- prePostEnabled(启用
@PreAuthorize
/@PreFilter
/@PostAuthorize
/@PostFilter
) - securedEnabled(启用
@Secured
) - jsr250Enabled(用于启用 JSR-250 注释,例如
@DenyAll
、@PermitAll
、@RolesAllowed
) - 自定义一个
MethodSecurityMetadataSource
由于您只在现有配置中启用 prePostEnabled
,我相信您现在不应在任何方法上使用任何 @Secured
和 JSR-250 注释。
所以下面的技巧应该只禁用 @PreAuthorize
,同时保持其他东西不变:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = false, securedEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
或
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = false, jsr250Enabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
测试的“切换”代码 (un-/commenting) 是不行的! (在“严格的团队”中,您甚至可能不会提交注释代码!-> sonarqube)
在复杂(分布式)环境中,具有 (spring) @Profile("test")
(例如关闭安全性)听起来绝对合法!
(单元+集成)测试您的安全性(+配置)仍然是[非常好-必不可少]!
Spring Security 5.5.x Reference Documentation, Chapter 19 Testing
This section describes the testing support provided by Spring Security.
19.1. Testing Method Security
Before we can use Spring Security Test support, we must perform some setup. An example can be seen below:
@RunWith(SpringJUnit4ClassRunner.class) // 1. @ContextConfiguration // 2. public class WithMockUserTests { ...
(我们可以将两者合而为一:@SpringBootTest
;)
This is a basic example of how to setup Spring Security Test. The highlights are:
@RunWith
instructs the spring-test module that it should create an ApplicationContext. This is no different than using the existing Spring Test support. For additional information, refer to the Spring Reference@ContextConfiguration
instructs the spring-test the configuration to use to create the ApplicationContext. Since no configuration is specified, the default configuration locations will be tried. This is no different than using the existing Spring Test support. For additional information, refer to the Spring ReferenceSpring Security hooks into Spring Test support using the
WithSecurityContextTestExecutionListener
which will ensure our tests are ran with the correct user. It does this by populating theSecurityContextHolder
prior to running our tests. If you are using reactive method security, you will also needReactorContextTestExecutionListener
which populatesReactiveSecurityContextHolder
. After the test is done, it will clear out theSecurityContextHolder
. If you only need Spring Security related support, you can replace@ContextConfiguration
with@SecurityTestExecutionListeners
.请记住,我们向
HelloMessageService
添加了@PreAuthorize
注释,因此它需要经过身份验证的用户才能调用它。如果我们 运行 下面的测试,我们期望下面的测试会通过:@Test(expected = AuthenticationCredentialsNotFoundException.class) public void getMessageUnauthenticated() { messageService.getMessage(); }
(测试预期(身份验证)异常!),所以其中之一:
19.1.2. @WithMockUser
...
19.1.3. @WithAnonymousUser
...
19.1.4. @WithUserDetails
...
19.1.5. @WithSecurityContext
...
19.1.6. Test Meta Annotations
...以及 chapter/reference 的其余部分将很有用。