ring端点时如何防止NestedServletExceptio

ring端点时如何防止NestedServletExceptio

本文介绍了测试Spring端点时如何防止NestedServletException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试测试某些受@PreAuthorize(#oauth2.hasScope('scope')保护的端点的安全配置.当通过Postman使用不具有所需范围的访问令牌访问此类端点时,将返回以下HTTP状态代码403(禁止):

I am trying to test the security configuration of some of my endpoints which are secured with @PreAuthorize(#oauth2.hasScope('scope'). When accessing such an endpoint via Postman with a access token that does not have the required scope, the following is returned with HTTP status code 403 (forbidden):

{
    "error": "insufficient_scope",
    "error_description": "Insufficient scope for this resource",
    "scope": "scope"
}

这是我想要的预期行为.

Which is the expected behaviour that I want.

当尝试测试此配置时,Springs NestedServletException会在无法完成我的预期结果之前干扰我的测试用例.

When trying to test this configuration, Springs NestedServletException interferes with my test case before it can complete with my expected result.

这是我要测试的控制器的简化版本:

This is a simplified version of the controller I want to test:

@RestController
@RequestMapping(value = "/api")
public class OauthTestingResource {

    @PreAuthorize(#oauth2.hasScope('scope'))
    @RequestMapping(value = "/scope", method = RequestMethod.GET)
    public void endpoint() {
        // ...
    }
}

这是相应的测试用例:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = MyApplication.class)
@WebAppConfiguration
public class AuthorizationTest {

    @Autowired
    protected WebApplicationContext webApplicationContext;

    protected SecurityContext securityContext = Mockito.mock(SecurityContext.class);

    @Before
    public void setup() throws Exception {

        this.mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        SecurityContextHolder.setContext(securityContext);
    }

    protected Authentication createMockAuth(Client client) {

        final List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));

        final Authentication pwAuth = new UsernamePasswordAuthenticationToken("testuser", "testpw", authorities);

        final TokenRequest request = new TokenRequest(new HashMap<>(), client.getClientId(), client.getScopes(), "password");

        final OAuthClient oauthClient = new OAuthClient(client, GrantType.PASSWORD);

        return new OAuth2Authentication(request.createOAuth2Request(oauthClient), pwAuth);
    }
    @Test
    public void testAppScope() throws Exception {

        final Client client = new Client("id1", "secret1");

        client.setScope("scope");
        Mockito.when(securityContext.getAuthentication()).thenReturn(createMockAuth(client));
        // this test passes
        mvc.perform(get("/api/scope")).andExpect(status().isOk());

        client.setScope("other_scope");
        Mockito.when(securityContext.getAuthentication()).thenReturn(createMockAuth(client));
        // NestedServletException thrown here
        mvc.perform(get("/api/scope")).andExpect(status().isForbidden());
    }
}

引发的异常如下(预期):

The exception that is thrown is the following (which is expected):

我的问题是如何防止此异常干扰我的测试用例?

推荐答案

我通过遵循链接.除了在NestedServletException中嵌套原始异常的问题以外,其他一切工作正常.我没有找到解决这个问题的任何直接方法,但是AspectJ帮助我以一种更简洁的方式进行处理.

I did spring security test cases by following this link. Things worked fine except this issue of nesting original exception in NestedServletException.I did not find any direct way to figure this out but AspectJ helped me in handling this in a cleaner way.

我们可以使用Assertions类的静态assertThatThrownBy()方法.此方法返回一个AbstractThrowableAssert对象,我们可以用来为抛出的异常编写断言.

We can use the static assertThatThrownBy() method of the Assertions class. This method returns an AbstractThrowableAssert object that we can use to write assertions for the thrown exception.

捕获方法ThatThrowsException()方法引发的异常的代码如下:

The code that captures an exception thrown by the methodThatThrowsException() method looks as follows:

assertThatThrownBy(() -> methodThatThrowsException())
.isExactlyInstanceOf(DuplicateEmailException.class);

感谢优秀的博客,您可以在其中找到更多详细信息.

Thanks to this excellent blog where you can find additional details.

我在测试用例中处理此问题的方式将是(通过采用您的测试用例代码行):

The way in which I handled this in my test case would be (by taking your test case codeline):

org.assertj.core.api.Assertions.assertThatThrownBy(() -> mvc.perform(get("/api/scope")).andExpect(status().isOk())).hasCause(new AccessDeniedException("Access is denied"));

这样,您的测试用例便可以声明嵌套在NestedServletException中的实际AccessDeniedException.

That way your test case would be able to assert actual AccessDeniedException that is nested in NestedServletException.

这篇关于测试Spring端点时如何防止NestedServletException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!