[英]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 Email
和Password
正确传递
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 这意味着您的测试用例的
username
和password
与UserRepository
类用户详细信息不匹配
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.