Spring Boot:如何在身份验证之前运行Bean验证?

时间:2018-05-04 18:10:49

标签: java spring authentication spring-boot bean-validation

我是Spring Boot的新手。

我想知道如何在Spring Boot中进行身份验证之前验证凭证DTO?

我有这个控制器:

@PostMapping
public ResponseEntity<TokenDTO> generateTokenJwt(@Valid @RequestBody CredentialsDTO credentials, BindingResult result)
        throws AuthenticationException {

    TokenDTO response = new TokenDTO();

    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
            credentials.username, credentials.password);

    Authentication authentication = authenticationManager.authenticate(authenticationToken);

    SecurityContextHolder.getContext().setAuthentication(authentication);

    UserDetails userDetails = userDetailsService.loadUserByUsername(credentials.username);

    String token = jwtTokenUtils.getToken(userDetails);

    response.token = token;

    return ResponseEntity.ok(response);
}

证书DTO是:

public class CredentialsDTO {

    @NotEmpty
    public String username;

    @NotEmpty
    public String password;

}

所以,当我像这样执行POST时:

curl -i -X POST \
   -H "Accept:application/json" \
   -H "Content-Type:application/json" \
   -d \
'{
    "username": "",
    "password": "123456"
}' \
 'http://localhost:8080/api/login'

我想显示422错误,告知用户名属性不应为空,但是,发生的情况是首先进行身份验证,返回的错误是401.

2 个答案:

答案 0 :(得分:1)

您可以添加HandlerInterceptor的实现。

您的preHandle(...)方法的实现应该处理错误场景,然后返回false(以阻止请求被传递给其他侦听器和处理程序)。

您可以扩展HandlerInterceptorAdapter以使生活更轻松。这看起来像这样。

@Component
public class LoginInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(isRequestToLoginUrl(request)) {
            return hasValidBody(request);
        }
        return true;
    }
}

然后你必须在Spring MVC中注册该处理程序,添加:

@Configuration
public static class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(loginInterceptor);
    }
}

答案 1 :(得分:1)

我认为问题是Spring在到达Post方法之前处理身份验证。因此,永远不会在CredentialsDTO

上执行Bean验证

我建议你创建自己的UserDetailsS​​ervice。这将使您能够对身份验证进行一些验证。

示例:

@Service
@Transactional(propagation = Propagation.REQUIRED)
public class UserSecurityService implements UserDetailsService {

    @Autowired
    UserRepository userRepository;

    public User loadUserByUsername(String email) throws UsernameNotFoundException {

        if (email.isEmpty()) {
        //Throw whatever exception you see fitting
            throw new UsernameNotFoundException("security.userNotFound");
        }

        User user = userRepository.getUserByEmail(email);

        return user;
    }

}