Testing an OAuth Secured API with Spring MVC (using the Spring Security OAuth legacy stack) – 用Spring MVC测试OAuth安全的API(使用Spring Security OAuth遗留栈)。

最后修改: 2017年 3月 17日

1. Overview


In this article, we’re going to show how we can test an API which is secured using OAuth with the Spring MVC test support.

在这篇文章中,我们将展示如何在Spring MVC测试支持下测试使用OAuth安全的API

Note: this article is using the Spring OAuth legacy project.

注意:本文使用的是Spring OAuth遗留项目

2. Authorization and Resource Server


For a tutorial on how to setup an authorization and resource server, look through this previous article: Spring REST API + OAuth2 + AngularJS.

关于如何设置授权和资源服务器的教程,请翻阅之前的这篇文章。Spring REST API + OAuth2 + AngularJS

Our authorization server uses JdbcTokenStore and defined a client with id “fooClientIdPassword” and password “secret”, and supports the password grant type.


The resource server restricts the /employee URL to the ADMIN role.

资源服务器将/employee URL限制为ADMIN角色。

Starting with Spring Boot version 1.5.0 the security adapter takes priority over the OAuth resource adapter, so in order to reverse the order, we have to annotate the WebSecurityConfigurerAdapter class with @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER).

从Spring Boot 1.5.0版本开始,安全适配器的优先级高于OAuth资源适配器,因此为了颠倒顺序,我们必须在WebSecurityConfigurerAdapter类中注解@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)

Otherwise, Spring will attempt to access requested URLs based on the Spring Security rules instead of Spring OAuth rules, and we would receive a 403 error when using token authentication.

否则,Spring会根据Spring Security规则而不是Spring OAuth规则尝试访问请求的URL,在使用令牌认证时,我们会收到一个403错误。

3. Defining a Sample API


First, let’s create a simple POJO called Employee with two properties that we will manipulate through the API:


public class Employee {
    private String email;
    private String name;
    // standard constructor, getters, setters

Next, let’s define a controller with two request mappings, for getting and saving an Employee object to a list:


public class EmployeeController {

    private List<Employee> employees = new ArrayList<>();

    public Optional<Employee> getEmployee(@RequestParam String email) {
        return employees.stream()
          .filter(x -> x.getEmail().equals(email)).findAny();

    public void postMessage(@RequestBody Employee employee) {

Keep in mind that in order to make this work, we need an additional JDK8 Jackson module. Otherwise, the Optional class will not be serialized/deserialized properly. The latest version of jackson-datatype-jdk8 can be downloaded from Maven Central.

请记住,为了使其工作,我们需要一个额外的JDK8 Jackson模块。否则,Optional类将不能被正确序列化/反序列化。最新版本的jackson-datatype-jdk8可以从Maven中心下载。

4. Testing the API


4.1. Setting Up the Test Class


To test our API, we will create a test class annotated with @SpringBootTest that uses the AuthorizationServerApplication class to read the application configuration.


For testing a secured API with Spring MVC test support, we need to inject the WebAppplicationContext and Spring Security Filter Chain beans. We’ll use these to obtain a MockMvc instance before the tests are run:

对于使用Spring MVC测试支持测试安全的API,我们需要注入WebAppplicationContextSpring Security Filter Chain Bean。我们将使用这些来在测试运行前获得一个MockMvc实例。

@SpringBootTest(classes = AuthorizationServerApplication.class)
public class OAuthMvcTest {

    private WebApplicationContext wac;

    private FilterChainProxy springSecurityFilterChain;

    private MockMvc mockMvc;

    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)

4.2. Obtaining an Access Token


Simply put, an APIs secured with OAuth2 expects to receive a the Authorization header with a value of Bearer <access_token>.

简单地说,用OAuth2担保的API 希望收到一个Authorization,值为Bearer <access_token>

In order to send the required Authorization header, we first need to obtain a valid access token by making a POST request to the /oauth/token endpoint. This endpoint requires an HTTP Basic authentication, with the id and secret of the OAuth client, and a list of parameters specifying the client_id, grant_type, username, and password.

为了发送所需的Authorization头,我们首先需要向/oauth/token端点发出POST请求,从而获得一个有效的访问令牌。这个端点需要一个HTTP Basic认证,包括OAuth客户端的id和secret,以及指定client_idgrant_typeusernamepassword的参数列表。

Using Spring MVC test support, the parameters can be wrapped in a MultiValueMap and the client authentication can be sent using the httpBasic method.

使用Spring MVC测试支持,参数可以被包裹在一个MultiValueMap中,客户端认证可以使用httpBasic方法发送。

Let’s create a method that sends a POST request to obtain the token and reads the access_token value from the JSON response:


private String obtainAccessToken(String username, String password) throws Exception {
    MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
    params.add("grant_type", "password");
    params.add("client_id", "fooClientIdPassword");
    params.add("username", username);
    params.add("password", password);

    ResultActions result 
      = mockMvc.perform(post("/oauth/token")

    String resultString = result.andReturn().getResponse().getContentAsString();

    JacksonJsonParser jsonParser = new JacksonJsonParser();
    return jsonParser.parseMap(resultString).get("access_token").toString();

4.3. Testing GET and POST Requests


The access token can be added to a request using the header(“Authorization”, “Bearer “+ accessToken) method.

访问令牌可以使用header(“Authorization”, “Bearer “+ accessToken)方法添加到请求中。

Let’s attempt to access one of our secured mappings without an Authorization header and verify that we receive an unauthorized status code:


public void givenNoToken_whenGetSecureRequest_thenUnauthorized() throws Exception {
      .param("email", EMAIL))

We have specified that only users with a role of ADMIN can access the /employee URL. Let’s create a test in which we obtain an access token for a user with USER role and verify that we receive a forbidden status code:

我们已经指定,只有角色为ADMIN的用户可以访问/employee URL。让我们创建一个测试,在这个测试中,我们获得一个具有USER角色的用户的访问令牌,并验证我们是否收到forbidden状态代码。

public void givenInvalidRole_whenGetSecureRequest_thenForbidden() throws Exception {
    String accessToken = obtainAccessToken("user1", "pass");
      .header("Authorization", "Bearer " + accessToken)
      .param("email", "j[email protected]"))

Next, let’s test our API using a valid access token, by sending a POST request to create an Employee object, then a GET request to read the object created:


public void givenToken_whenPostGetSecureRequest_thenOk() throws Exception {
    String accessToken = obtainAccessToken("admin", "nimda");

    String employeeString = "{\"email\":\"[email protected]\",\"name\":\"Jim\"}";
      .header("Authorization", "Bearer " + accessToken)

      .param("email", "[email protected]")
      .header("Authorization", "Bearer " + accessToken)
      .andExpect(jsonPath("$.name", is("Jim")));

5. Conclusion


In this quick tutorial, we have demonstrated how we can test an OAuth-secured API using the Spring MVC test support.

在这个快速教程中,我们已经演示了如何使用Spring MVC测试支持来测试一个OAuth安全的API。

The full source code of the examples can be found in the GitHub project.


To run the test, the project has an mvc profile that can be executed using the command mvn clean install -Pmvc.

为了运行测试,该项目有一个mvc配置文件,可以使用mvn clean install -Pmvc.命令执行。