收到错误org.springframework.security.authentication.BadCredentialsException

时间:2019-02-13 09:45:06

标签: spring-security jwt

我们已经在Angular + Spring Boot + JPA项目中实现了Spring Security 但是登录时遇到以下异常-从邮递员运行时进行身份验证:-

`trace": "org.springframework.security.authentication.BadCredentialsException: Bad credentials\r\n\tat org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:93)\r\n\tat org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:166)\r\n\tat org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175)\r\n\tat org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:200)\r\n\tat org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:503)\r\n\tat com.jwt.security.controller.AuthenticationController.login(AuthenticationController.java:40)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)\r\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)\r\n\tat java.lang.reflect.Method.invoke(Unknown Source)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:90

表示网址:http://localhost:8080/login 和身体 : { “电子邮件”:“ abcd@test.com”, “密码”:“ 123” }

代码如下

SecurityConfiguration.java是配置类

package com.jwt.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.csrf.CsrfFilter;

import com.jwt.security.filter.AuthenticationTokenFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration<jwtAuthenticationEntryPoint>  extends WebSecurityConfigurerAdapter{

    @Autowired private UserDetailsService userDetailsService;

    @Autowired private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint ; 

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(this.userDetailsService).passwordEncoder( passwordEncoder());       
    }

    @Bean
    public PasswordEncoder passwordEncoder() {  
        return new BCryptPasswordEncoder();
    }

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

    @Bean 
    public AuthenticationTokenFilter authenticationTokenFilterBean( ) {
        return new AuthenticationTokenFilter(); 
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception    {
        httpSecurity.csrf().disable()
        .exceptionHandling()
        .authenticationEntryPoint(jwtAuthenticationEntryPoint).and()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
        .authorizeRequests()
        .antMatchers("/**").permitAll()
        .antMatchers("/registration").permitAll()
        .antMatchers("/login").permitAll()
        .antMatchers(HttpMethod.OPTIONS ,"/**").permitAll()
        .anyRequest().authenticated();
        httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
        .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
        httpSecurity.headers().cacheControl();
        httpSecurity.headers().httpStrictTransportSecurity().includeSubDomains(true).maxAgeInSeconds(31536000);       
    }
}

JwtAuthenticationEntryPoint.java

package com.jwt.security;

import java.io.IOException;
import java.io.Serializable;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint , Serializable {

    /**
     *       
     */
    private static final long serialVersionUID = 3293526539341241958L;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Unauthorized");

    }

}

JwtTokenUtil.java代码在下面

package com.jwt.security;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class JwtTokenUtil implements Serializable {

    static final String CLAIM_KEY_USERNAME = "sub";
    static final String CLAIM_KEY_AUDIENCE = "audience";
    static final String CLAIM_KEY_CREATED = "created";

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private Long expiration;

    public String getUsernameFromToken(String authToken) {
        String username = null;
        try {
            final Claims claims = getClaimsFromToken(authToken);
            username = claims.getSubject();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            username = null;
        }
        return username;
    }

    private Claims getClaimsFromToken(String authToken) {
        // TODO Auto-generated method stub
        Claims claims = null;
        try {
            claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(authToken).getBody();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            claims = null;
        }

        return claims;
    }

    public boolean validateToken(String authToken, UserDetails userDetails) {
        // TODO Auto-generated method stub
        JwtUser user = (JwtUser) userDetails;
        final String username = getUsernameFromToken(authToken);
        return (username.equals(user.getUsername()) && !isTokenExpired(authToken));

    }

    private boolean isTokenExpired(String authToken) {
        final Date expiration = getExpirationDateFromToken(authToken);
        return expiration.before(new Date());
    }

    private Date getExpirationDateFromToken(String authToken) {
        // TODO Auto-generated method stub
        Date expiration = null;
        final Claims claims = getClaimsFromToken(authToken);
        if (claims != null) {
            expiration = claims.getExpiration();
        } else {
            expiration = null;
        }
        return expiration;
    }
    public String generateToken(JwtUser userDetails) {
        Map<String,Object> claims = new HashMap<String,Object>();
        claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);

    }

    public String generateToken(Map<String , Object> claims ) {
        return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate()).signWith(SignatureAlgorithm.HS512, secret).compact();
    }

    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }
}

JwtUser实现UserDetails

package com.jwt.security;

import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.jwt.security.domain.User;

public class JwtUser  implements UserDetails {

    private final Long id;
    private final String username;
    private final String password;
    private final User user;
    private final boolean enabled;
    private final Collection <? extends GrantedAuthority > authorities;



    public JwtUser(Long id, String username, String password, User user, boolean enabled,
            Collection<? extends GrantedAuthority> authorities) {
        super();
        this.id = id;
        this.username = username;
        this.password = password;
        this.user = user;
        this.enabled = enabled;
        this.authorities = authorities;
    }

    @Override
    public String getPassword() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getUsername() {
        // TODO Auto-generated method stub
        return null;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonExpired() {
        // TODO Auto-generated method stub
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonLocked() {
        // TODO Auto-generated method stub
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isCredentialsNonExpired() {
        // TODO Auto-generated method stub
        return true;
    }
    @Override
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return enabled;

    }
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // TODO Auto-generated method stub
        return authorities;
    }

    @JsonIgnore
    public Long getId() {
        return id;
    }
    public User getUser() {
        return user;
    }

    @Override
    public String toString() {
        return "JwtUser [id=" + id + ", username=" + username + ", password=" + password + ", user=" + user
                + ", enabled=" + enabled + ", authorities=" + authorities + "]";
    }

}

JwtUserDetailsS​​erviceImpl是服务

/**
 * 
 */
package com.jwt.security;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.jwt.security.domain.User;
import com.jwt.security.repository.UserRepository;


@Service
public class JwtUserDetailsServiceImpl implements UserDetailsService {

    //@Autowired private UserRepository userRepository;

    @Autowired UserRepository userRepository;
/*      private static final AtomicLong counter = new AtomicLong();

        private static List<User> users;
        static {
            users = populateDummyUsers();
        }

        private static List<User> populateDummyUsers() {
            List<User> users = new ArrayList<User>();
            return users;
        }
*/

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //User userdb = null;
        User  userdb = userRepository.findByEmailIgnoreCase(username);
        UserDetails details = null;
    /*  for (User user : users) {
            if (user.getEmail() == username) {
                userdb = user;
            }
        }*/


        if(username == null) {
            throw new UsernameNotFoundException(String.format("No User found with username '%s'.", username));          
        }else {
            details= JwtuserFactory.create(userdb);
            System.out.println("details" + details);
            return details;
        }
    }

}

JwtuserFactory.java如下

package com.jwt.security;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import com.jwt.security.domain.User;

public class JwtuserFactory {

    public static JwtUser create(User user) {
        // TODO Auto-generated method stub
        return new JwtUser(user.getId(), user.getEmail(), user.getPassword(), user, user.isEnabled(), maptoGrantedAuthorities(new ArrayList<String>(Arrays.asList("ROLE_" + user.getRole()))));
    }

    private static List<GrantedAuthority> maptoGrantedAuthorities(List<String> authorities) {
        // TODO Auto-generated method stub
        return authorities.stream().map(Authority -> new SimpleGrantedAuthority(Authority)).collect(Collectors.toList());
    }

}

AuthenticationController代码如下

package com.jwt.security.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.jwt.security.JwtTokenUtil;
import com.jwt.security.JwtUser;
import com.jwt.security.domain.User;
import com.jwt.security.domain.UserDTO;
import com.jwt.security.exception.UnauthorizedException;

@RestController
public class AuthenticationController {

    @Value("${jwt.header}")
    private String tokenHeader;

    @Autowired private AuthenticationManager authenticationManager; 
    @Autowired private JwtTokenUtil jwtTokenUtil;

    @PostMapping(value="/login")
    public ResponseEntity<UserDTO> login(@RequestBody User user, HttpServletRequest request , HttpServletResponse response) {
    try {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        //System.out.println("matches ::" + encoder.matches("123", user.getPassword()));
        System.out.println("User entered password" + user.getPassword() );
        Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword()));
        final JwtUser userDetails = (JwtUser)authentication.getPrincipal();
        SecurityContextHolder.getContext().setAuthentication(authentication);
        final String token = jwtTokenUtil.generateToken(userDetails);
        response.setHeader("Token", token);
        return new ResponseEntity<UserDTO>(new UserDTO(userDetails.getUser(), token) , HttpStatus.OK);
    }catch(UnauthorizedException ex) {
        ex.printStackTrace();
        throw new UnauthorizedException(ex.getMessage());
    }
    }           
}

AuthenticationTokenFilter为:-

package com.jwt.security.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import com.jwt.security.JwtTokenUtil;

public class AuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Value("${jwt.header}")
    private String tokenHeader;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        String authToken = request.getHeader(this.tokenHeader);
        if (authToken != null && authToken.length() > 7) {
            authToken = authToken.substring(7);
        }
        String username = jwtTokenUtil.getUsernameFromToken(authToken);
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            boolean isValid = jwtTokenUtil.validateToken(authToken, userDetails);
            if (isValid) {
                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
        }
        filterChain.doFilter(request, response);
    }

}

PasswordUtil如下:

package com.jwt.security.util;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class PasswordUtil {
    static BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

    public static String getPasswordHash(String password) {
        return encoder.encode(password);
    }

}

在数据库中,密码以加密方式存储。即使传递正确的参数,它也会产生BadCredentials错误

请提出建议并提供解决方案,以使身份验证可用于登录

1 个答案:

答案 0 :(得分:0)

您的JwtUser getPassword()getUsername()方法都返回null,但是在您当前的设置中,getPassword()导致了异常。

您将获得一个BadCredentialsException,因为默认的DaoAuthenticationProvider将使用提供的密码和使用UserDetailsService检索到的密码进行检查,并且返回的密码为null。 / p>