简体   繁体   English

Spring返回401而不是200状态

[英]Spring returns 401 instead of 200 status

I wrote an application as part of learning Spring, but when I test authentication I receive 401 status instead of 200. I was looking for the cause of the error and it seems to me that the line Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(email, password)); 我写了一个应用程序作为学习Spring的一部分,但是当我测试身份验证时,我收到401状态而不是200.我正在寻找错误的原因,在我看来,行Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(email, password)); returns null . 返回null However, I do not know how to solve this problem. 但是,我不知道如何解决这个问题。

@Component
public class AuthenticationServiceUsernamePassword {
    private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationServiceUsernamePassword.class);
    @Autowired
    @Qualifier("customAuthenticationManager")
    private AuthenticationManager authenticationManager;
    @Autowired
    private TokenManager tokenManager;

    public SignedJWT authenticate(final String email, final String password){
        try {
            Authentication authentication = authenticationManager
                .authenticate(new UsernamePasswordAuthenticationToken(email, password));        
            SecurityContextHolder.getContext()
                .setAuthentication(authentication);

            if (authentication.getPrincipal() != null) {
                return tokenManager.createNewToken((PrincipalUser) authentication.getPrincipal());
            }
        } catch (AuthenticationException authException) {
            LOGGER.debug("Authentication failed for user:\"" + email + ".\" Reason " + authException.getClass());
        }

        return null;
    }
}

Controller 调节器

@Controller
public class AuthController {
    @Value("${jwt.result}")
    private String defaultTokenResponse;
    @Autowired
    private AuthenticationServiceUsernamePassword authUserPassword;

    @RequestMapping(value = "/authentication", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> authenticate(String email, String password, HttpServletRequest request,
                                           HttpServletResponse response){
        if (email != null && password != null){
            try {
                SignedJWT token = authUserPassword.authenticate(email, password);

                if (token != null){
                    return new ResponseEntity<String>(String.format(defaultTokenResponse, token.serialize()),
                        HttpStatus.OK);
                } else {
                    return new ResponseEntity<String>(HttpStatus.UNAUTHORIZED);
                }
            } catch (BadCredentialsException badCredentials) {
                return new ResponseEntity<String>(HttpStatus.UNAUTHORIZED);
            }
        } else {
            return new ResponseEntity<String>(HttpStatus.UNAUTHORIZED);
        }
    }
}

Test class: 测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
@WebAppConfiguration
public class ConnectControllerTest {
    protected MockMvc mockMvc;
    @Autowired
    private WebApplicationContext context;
    @Autowired
    private Filter springSecurityFilterChain;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(context)
            .addFilters(springSecurityFilterChain)
            .defaultRequest(get("/"))
            .build();
    }

    @Test
    public void shouldTestAuthentication() throws Exception {
        String result = mockMvc.perform(post("/authentication")
            .param("email", "user@test.pl").param("password", "password"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.token").exists())
            .andReturn().getResponse().getContentAsString();
    }
}

If anyone would be interested in the rest of the code here is the link: repository 如果有人对其余的代码感兴趣,那么链接: repository

Ok. 好。 First thing first 首先是第一件事

Email and Password are passed correctly EmailPassword正确传递

Problem is here 问题在这里

public SignedJWT authenticate(final String email, final String password){
        try {
            System.out.println("test => "+email+" : "+password);
            Authentication authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(email, password));
            SecurityContextHolder.getContext().setAuthentication(authentication);

            if (authentication.getPrincipal() != null) {
                return tokenManager.createNewToken((PrincipalUser) authentication.getPrincipal());
            }
        } catch (AuthenticationException authException) {
            authException.printStackTrace();
            LOGGER.debug("Authentication failed for user:\"" + email + ".\" Reason " + authException.getClass());
        }
        System.out.println("return nulll");
        return null;
    }

If you run your test case it will throw following error 如果运行测试用例,则会抛出以下错误

org.springframework.security.authentication.BadCredentialsException: Bad credentials
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:98)
    at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:166)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:504)
    at com.github.springjwt.security.jwt.service.AuthenticationServiceUsernamePassword.authenticate(AuthenticationServiceUsernamePassword.java:30)
    at com.github.springjwt.web.api.controller.AuthController.authenticate(AuthController.java:31)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImp

Which means your testcase's username and password didnt match with UserRepository class User detail 这意味着您的测试用例的usernamepasswordUserRepository类用户详细信息不匹配

In your UserRepository class you need to set a correct hashed password and its salt value which you have set to null. UserRepository类中,您需要设置正确的散列密码及其设置为null的salt值。

When you call authenticate.authenticate it internally gets password and hash and matched it with passed value. 当您调用authenticate.authenticate它会在内部获取密码和哈希值,并将其与传递的值进行匹配。

If values doesn't match it throws Bad credentials error 如果值不匹配则抛出错误凭据错误

PS : I came to this conclusion after running your code locally PS:我在本地运行代码后得出了这个结论

Your code is mostly correct, it goes wrong in your controller definition: 您的代码大多是正确的,它在您的控制器定义中出错了:

public ResponseEntity<String> authenticate(String email, String password, HttpServletRequest request,
                                           HttpServletResponse response){

Spring does not know how to retrieve the email and password variables by default. Spring默认不知道如何检索电子邮件和密码变量。 You need to annotate these with the @RequestBody annotation, like: 您需要使用@RequestBody注释来注释这些注释,例如:

public ResponseEntity<String> authenticate(@RequestBody String email, @RequestBody String password, HttpServletRequest request,
                                           HttpServletResponse response){

However if your whole controller will serve as an API you can also annotate your controller with @RestController which tells spring to use the @RequestBody for every parameter and that every method should be annotated with @ResponseBody which will tell spring that the return values should be converted to JSON (which is convenient for an API). 但是,如果您的整个控制器将作为API使用,您还可以使用@RestController注释您的控制器,它告诉spring为每个参数使用@RequestBody ,并且每个方法都应该使用@ResponseBody进行注释,这将告诉spring返回值应该是转换为JSON(方便API)。

References: 参考文献:

Spring's RequestBody and ResponseBody Annotations Spring的RequestBody和ResponseBody注释

You have added params to you unit test case. 您已将params添加到单元测试用例中。 Not payload. 没有负载。 If you add payload then you have to use @RequestBody. 如果添加有效负载,则必须使用@RequestBody。 Here you have to use @RequestParam. 在这里你必须使用@RequestParam。 Use below code in controller : 在控制器中使用以下代码:

public ResponseEntity<String> authenticate(@RequestParam String email, @RequestParam String password, HttpServletRequest request,HttpServletResponse response){
 ..do stuff
}

This will work ..! 这将工作..!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring Boot,Spring Security 返回状态 401 而不是 404,用于“未找到 HTTP 请求的映射” - Spring Boot, Spring Security returns a status 401 instead of 404 for "no mapping found for HTTP request" Microprofile JWT web.xml 返回 200 而不是 401 - Microprofile JWT web.xml returns 200 instead of 401 带有Spring MVC的jUnit返回400而不是200 - jUnit with Spring MVC returns a 400 instead a 200 Spring 安全返回 200 而不是 401,如 HttpWebHandlerAdapter 所述 - Spring Security returning 200 instead of 401 as stated by HttpWebHandlerAdapter Java Spring Controller映射正确,但是服务器返回302而不是200 - Java Spring Controller mapped properly, but server returns 302 instead of 200 Spring Boot - Jackson EntityNotFoundException 返回 200 而不是 500 响应 - Spring Boot - Jackson EntityNotFoundException returns 200 instead of 500 response Spring 引导单元测试返回 404 而不是 200 - Spring Boot Unit Test returns 404 instead of 200 Spring Boot WebMvcTest 返回 302 而不是 GET 方法的 401 - Spring Boot WebMvcTest returns 302 instead of 401 for GET methods HttpGet 401状态码,后跟200状态码 - HttpGet 401 status code followed by 200 status code 单元测试没有按预期工作 - 而不是 404,它返回 200 作为状态码 - Unit test does not work as expected - instead of 404, it returns 200 as status code
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM