spring-security AuthenticationManager返回错误的凭据

ilmyapht  于 2022-11-11  发布在  Spring
关注(0)|答案(1)|浏览(276)

我有这个错误,我不知道它可能是什么。我按照教程做用户身份验证,但当我尝试做身份验证时,它抛出了一个“错误的凭据”,但凭据是正确的。我正在使用MongoDB。
从教程中,我遵循这些步骤,它应该工作(其他用户确认他们这样做),但唯一的事情,我做了不同于教程是在“ClientEntity”类已经存在,我只是实现了我需要的。
用户退货:

ClientEntity(id=63166ddbe3ea6c4fffd70818, clientName=Test, clientCpf=000.000.000-00, clientEmail=teste2@example.com, clientPassword=2b598e4c0e79baf9dc9211ad303e7626, clientIsBlocked=false, clientBirthDate=1989-05-20, creditCards=[CreditCardEntity()], clientCategory=[ACAO, COMEDIA])

我的登录请求,我通过电子邮件和密码登录:

AccountCredentials: AccountCredentials(email=teste2@example.com, password=2b598e4c0e79baf9dc9211ad303e7626)

我知道问题出在**“authenticationManager.authenticate(新用户名密码authenticationToken(电子邮件,密码))中的那个类中;“**但我不知道怎么解决它,因为凭据是正确的
我的身份验证服务类:

@Service
public class AuthService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenProvider tokenProvider;

    @Autowired
    private ClientRepository repository;

    public ResponseEntity signin(AccountCredentials data) {
        try {
            var email = data.getEmail();
            var password = data.getPassword();
            log.info("METODO SIGNIN, AccountCredentials: " + data);

            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(email, password));

            log.info("FOI AUTENTICADO!");

            var user = repository.findByClientEmail(email);

            log.info("O valor de User é: " + user);

            var tokenResponse = new Token();
            if (user != null) {
                tokenResponse = tokenProvider.createAccessToken(email, user.getRoles());
            } else {
                throw new UsernameNotFoundException("Email " + email + " not found!");
            }
            return ResponseEntity.ok(tokenResponse);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            System.out.println(e.getCause());
            System.out.println(e.getLocalizedMessage());
            throw new BadCredentialsException("Invalid email/password supplied!");
        }
    }

    public ResponseEntity refreshToken(String email, String refreshToken) {
        var user = repository.findByClientEmail(email);
        var tokenResponse = new Token();
        if (user != null) {
            tokenResponse = tokenProvider.refreshToken(refreshToken);
        } else {
            throw new UsernameNotFoundException("Email " + email + " not found!");
        }
        return ResponseEntity.ok(tokenResponse);
    }
}

我的客户实体:

@Data
@Document(collection = "Client")
public class ClientEntity implements UserDetails, Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private String id;
    private String clientName;
    private String clientCpf;
    private String clientEmail;
    private String clientPassword;
    private boolean clientIsBlocked = false;
    private LocalDate clientBirthDate;
    private List<CreditCardEntity> creditCards;
    private List<ClientCategoryEnum> clientCategory;

    private List<Permission> permissions;

    public List<String> getRoles() {
        List<String> roles = new ArrayList<>();
        for (Permission permission : permissions) {
            roles.add("USER");
            roles.add(permission.getDescription());
        }
        return roles;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.permissions;
    }

    @Override
    public String getPassword() {
        return this.clientPassword;
    }

    @Override
    public String getUsername() {
        return this.clientEmail;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

我的班级权限:

@Data
@Document(collection = "Roles")
public class Permission implements GrantedAuthority, Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private Long id;
    private String description;

    @Override
    public String getAuthority() {
        return this.description;
    }

}

我的安全配置:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtTokenProvider tokenProvider;

    /*
    @Bean
    public UserDetailsService userDetailsService() {
        return super.userDetailsService();
    }
     */

    @Bean
    public PasswordEncoder passwordEncoder() {
        Map<String, PasswordEncoder> encoders = new HashMap<>();
        encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
        DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder("pbkdf2", encoders);
        passwordEncoder.setDefaultPasswordEncoderForMatches(new Pbkdf2PasswordEncoder());
        return passwordEncoder;
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .httpBasic().disable()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers(
                        "/auth/signin",
                        "/auth/refresh"
                ).permitAll()
                .antMatchers("/api/movie_search/**").authenticated()
                .and()
                .cors()
                .and()
                .apply(new JwtConfigurer(tokenProvider));
    }
}

我的类令牌提供程序:

@Service
public class JwtTokenProvider{
    @Value("${security.jwt.token.secret-key:secret}")
    private String secretKey = "secret";

    @Value("${security.jwt.token.expire-length:3600000}")
    private long validityInMilliseconds = 3600000; // 1h

    @Autowired
    private UserDetailsService userDetailsService;

    Algorithm algorithm = null;

    @PostConstruct
    protected void init() {
        secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
        algorithm = Algorithm.HMAC256(secretKey.getBytes());
    }

    public Token createAccessToken(String email, List<String> roles) {
        Date now = new Date();
        Date validity = new Date(now.getTime() + validityInMilliseconds);
        var accessToken = getAccessToken(email, roles, now, validity);
        var refreshToken = getRefreshToken(email, roles, now);

        return new Token(email, true, now, validity, accessToken, refreshToken);
    }

    public Token refreshToken(String refreshToken) {
        if (refreshToken.contains("Bearer ")) refreshToken =
                refreshToken.substring("Bearer ".length());

        JWTVerifier verifier = JWT.require(algorithm).build();
        DecodedJWT decodedJWT = verifier.verify(refreshToken);
        String email = decodedJWT.getSubject();
        List<String> roles = decodedJWT.getClaim("roles").asList(String.class);
        return createAccessToken(email, roles);
    }

    private String getAccessToken(String email, List<String> roles, Date now, Date validity) {
        String issuerUrl = ServletUriComponentsBuilder
                .fromCurrentContextPath().build().toUriString();
        return JWT.create()
                .withClaim("roles", roles)
                .withIssuedAt(now)
                .withExpiresAt(validity)
                .withSubject(email)
                .withIssuer(issuerUrl)
                .sign(algorithm)
                .strip();
    }

    private String getRefreshToken(String email,  List<String> roles, Date now) {
        Date validityRefreshToken = new Date(now.getTime() + (validityInMilliseconds * 3));
        return JWT.create()
                .withClaim("roles", roles)
                .withIssuedAt(now)
                .withExpiresAt(validityRefreshToken)
                .withSubject(email)
                .sign(algorithm)
                .strip();
    }

    public Authentication getAuthentication(String token) {
        DecodedJWT decodedJWT = decodedToken(token);
        UserDetails userDetails = this.userDetailsService
                .loadUserByUsername(decodedJWT.getSubject());
        return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
    }

    private DecodedJWT decodedToken(String token) {
        Algorithm alg = Algorithm.HMAC256(secretKey.getBytes());
        JWTVerifier verifier = JWT.require(alg).build();
        DecodedJWT decodedJWT = verifier.verify(token);
        return decodedJWT;
    }

    public String resolveToken(HttpServletRequest req) {
        String bearerToken = req.getHeader("Authorization");
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring("Bearer ".length());
        }
        return null;
    }

    public boolean validateToken(String token) {
        DecodedJWT decodedJWT = decodedToken(token);
        try {
            if (decodedJWT.getExpiresAt().before(new Date())) {
                return false;
            }
            return true;
        } catch (Exception e) {
            throw new InvalidJwtAuthenticationException("Expired or invalid JWT token!");
        }
    }
}

我的客户端服务:

@Service
public class ClientService implements UserDetailsService {

    private final ClientRepository clientRepository;

    private final ModelMapper modelMapper;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        var user = clientRepository.findByClientEmail(email);

        if (user != null) {
            return user;
        } else {
            throw new UsernameNotFoundException("Email " + email + " not found!");
        }
    }
}

**在调试过程中,我遇到了以下情况:**用户名密码验证令牌凭据=[PROTECTED],已验证=false,详细信息=null,授予的权限=[]]

zzlelutf

zzlelutf1#

**简短回答:**存储在数据库中的密码必须使用PasswordEncoder加密。
**详细答案:**您创建了PasswordEncoder类型的Bean,因此当您调用AuthenticationManager类的.authenticate()方法时,AuthenticationProvider将使用该Bean。

作为stated in java docsDelegatingPasswordEncoder希望您的密码以如下格式存储在DB中:
{编码器ID}加密密码
您使用pbkdf2密码编码器作为默认编码器,因此DB中的密码应如下所示:
{pbkdf 2}已加密密码
从返回的ClientEntity可以看出,在将该实体保存到DB时没有使用PasswordEncoder,因此存储的是原始密码而不是加密密码。
身份验证流程应如下所示:
1.您的应用注册一个用户,使用PasswordEncoder bean将其密码以 * 加密形式 * 存储在数据库中;
1.用户通过API端点的登录表单将其用户名(电子邮件或任何必要的东西)和 * 原始 * 密码传递给您的应用程序;

  1. AuthenticationProvider从数据库中检索 * 加密密码 *,并将其与用户提供的 * 原始 * 密码进行比较

相关问题