如何使用身份验证管理器修复“错误凭据”错误?
Posted
技术标签:
【中文标题】如何使用身份验证管理器修复“错误凭据”错误?【英文标题】:How to fix "Bad credentials" error using authentication manager? 【发布时间】:2021-06-30 06:33:20 【问题描述】:我正在做一个项目,您必须在其中注册一些用户并给他们一个角色(默认用户)。注册用户后,我添加了 jwt auth 并且能够获得 jwt 响应,但是在尝试对其执行一些过滤器后,代码开始失败。
此时我已经评论了过滤器实现方法以及我的 WebSecurityConfig。
假设我将在端点内收到用户名和密码(“authenticate/”)。
@RequestMapping(
value = "authenticate", "authenticate/",
method = RequestMethod.POST,
consumes =
MediaType.APPLICATION_FORM_URLENCODED_VALUE,
MediaType.MULTIPART_FORM_DATA_VALUE,
MediaType.APPLICATION_JSON_VALUE
,
produces = MediaType.APPLICATION_JSON_VALUE
)
public @ResponseBody AuthResponse login(AuthRequest authRequest) throws Exception
return this.authService.authenticate(authRequest);
AuthRequest 是用户名和密码。
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class AuthResponse
private String username;
private String password;
但错误是当我尝试使用 AuthenticationManager 对用户进行身份验证时。
AuthService 认证方法
public AuthResponse authenticate(AuthRequest authRequest) throws Exception
//System.out.println(authRequest.getUsername() +"," + authRequest.getPassword() + "," + this.bCryptPasswordEncoder.encode(authRequest.getPassword()));
try
this.authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())
);
catch (BadCredentialsException e)
//Here is the error
throw new Exception("Incorrect username or password", e);
final UserDetails userDetails = usersDetailService.loadUserByUsername(authRequest.getUsername());
final String jwt = jwtUtil.generateToken(userDetails);
//this.logService.save(new Log(null, userDetails.getUsername(), jwt, null));
System.out.println(jwt);
return new AuthResponse(jwt);
邮递员控制台内部出错。
"timestamp": "2021-04-03T19:23:01.510+00:00",
"status": 403,
"error": "Forbidden",
"trace": "java.lang.Exception: Incorrect username or password\n\tat com.cncipo.nl.auth.service.AuthService.authenticate2(AuthService.java:60)\n\tat com.cncipo.nl.controller.SessionRestController.auth(SessionRestController.java:85)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.lang.reflect.Method.invoke(Method.java:498)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:652)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)\n\tat org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)\n\tat org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)\n\tat org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)\n\tat org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:105)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)\n\tat org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)\n\tat org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)\n\tat org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)\n\tat org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)\n\tat org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)\n\tat org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tat java.lang.Thread.run(Thread.java:748)\nCaused by: org.springframework.security.authentication.BadCredentialsException: Bad credentials\n\tat org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:141)\n\tat org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)\n\tat org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:201)\n\tat org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:518)\n\tat com.cncipo.nl.auth.service.AuthService.authenticate2(AuthService.java:56)\n\t... 86 more\n",
"message": "Access Denied",
"path": "/api/authenticate"
我将添加 WebSecurityConfig 和 JwtFilter 以防我遗漏了某些内容并导致错误。
JwtFilter
//@Component
public class JwtRequestFilter extends OncePerRequestFilter
@Autowired
private UsersDetailService usersDetailService;
@Autowired
private JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
/* Get the header for auth */
final String authHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
System.out.println("Flag of header it's null when I implemented" + authHeader);
/* Extract jwt and username */
if (authHeader != null && authHeader.startsWith("Bearer "))
jwt = authHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
/* Extract user details */
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null)
UserDetails userDetails = this.usersDetailService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails))
/* Create default new jwt auth token */
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
/* Handling the control to the next filter chain */
filterChain.doFilter(request, response);
网络安全配置
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private UsersDetailService usersDetailService;
//@Autowired
//private JwtRequestFilter jwtRequestFilter;
@Bean
public BCryptPasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(usersDetailService);
/* Bean of AuthManager due to it used to work in older version of spring */
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Override
protected void configure(HttpSecurity http) throws Exception
/* Disable security */
http.csrf().disable();
/* User info page requires login as admin and user role. If no login, redirect */
http.authorizeRequests().antMatchers("users").access("hasAnyRole('admin', 'user')");
/* Only for admin */
http.authorizeRequests().antMatchers("logs", "admin").access("hasRole('admin')");
/* The pages does not require login/auth */
http.authorizeRequests().antMatchers("login", "logout", "/authenticate/, login/")
.permitAll();//.anyRequest().authenticated();
/* Using sessiong managment for intercept jwt auth . Spring won't create session, jwt will manage them*/
//http.exceptionHandling().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
UsersDetailService,MyUserDetails 实现 UserDetails from import org.springframework.security.core.userdetails.UserDetails;
@Service
public class UsersDetailService implements UserDetailsService
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
User user = this.userRepository.getUserByUsername_user(username);
if (user == null) throw new UsernameNotFoundException("Could not find user");
return new MyUserDetails(user);
【问题讨论】:
【参考方案1】:尝试以下设置:
在您的安全配置中
@Autowired
private JwtFilterRequest jwtFilterRequest;
@Override
protected void configure(HttpSecurity http) throws Exception
http.csrf().disable().authorizeRequests()
.antMatchers("/forgetPassword").permitAll()
.antMatchers("/registerUser").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and().exceptionHandling().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and().formLogin().loginPage("/login").loginProcessingUrl("/login")
.defaultSuccessUrl("/index.html").failureUrl("/login?error")
.and().logout().logoutUrl("/logout");
http.addFilterBefore(this.jwtFilterRequest, UsernamePasswordAuthenticationFilter.class);
过滤类JWT(JwtFilterRequest):
import cl.project.admin.security.jwt.JwtUtil;
import cl.project.admin.security.service.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtFilterRequest extends OncePerRequestFilter
@Autowired
private JwtUtil jwtUtil;
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
String authorizationHeader = request.getHeader("Authorization");
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer "))
String jwt = authorizationHeader.substring(7);
String username = this.jwtUtil.extractUsername(jwt);
if(username != null && SecurityContextHolder.getContext().getAuthentication() == null)
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if(this.jwtUtil.validateToken(jwt, userDetails))
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
filterChain.doFilter(request, response);
您的自定义 UserDetailService:
import cl.project.admin.controllers.AttentionController;
import cl.project.admin.models.dao.IUserDao;
import cl.project.admin.models.entity.User;
import cl.project.admin.models.service.UserServiceImpl;
import org.apache.log4j.Logger;
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 org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
@Service
public class CustomUserDetailsService implements UserDetailsService
Logger logger = Logger.getLogger(CustomUserDetailsService.class);
@Autowired
private UserServiceImpl userService;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
User user = userService.findByUsername(username);
if(user == null)
this.logger.error("Error al ingresar: " + username);
throw new UsernameNotFoundException(username);
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>());
JWT 实用程序
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Service
public class JwtUtil
@Value("$keyJWTSpringSecurity")
private static final String KEY = "passwordInYourApplicationProperties";
public String generateToken(UserDetails userDetail)
return Jwts.builder().setSubject(userDetail.getUsername()).setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 1000*60*60*5))
.signWith(SignatureAlgorithm.HS256, KEY).compact();
public String extractUsername(String token)
return extractClaim(token, Claims::getSubject);
public Date extractExpiration(String token)
return extractClaim(token, Claims::getExpiration);
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver)
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
private Claims extractAllClaims(String token)
return Jwts.parser().setSigningKey(KEY).parseClaimsJws(token).getBody();
private Boolean isTokenExpired(String token)
return extractExpiration(token).before(new Date());
public String generateToken(String username)
Map<String, Object> claims = new HashMap<>();
return createToken(claims, username);
public String generateTokenInfinity(String username)
Map<String, Object> claims = new HashMap<>();
return createTokenInfinity(claims, username);
private String createToken(Map<String, Object> claims, String subject)
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 5))
.signWith(SignatureAlgorithm.HS256, KEY).compact();
private String createTokenInfinity(Map<String, Object> claims, String subject)
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 800))
.signWith(SignatureAlgorithm.HS256, KEY).compact();
public Boolean validateToken(String token, UserDetails userDetails)
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
【讨论】:
非常感谢亚历克斯!我只有一个疑问。如何仅针对管理员角色限制某些端点(用户、管理员等)?如果离开这个 permitAll().anyRequest().authenticated() 我得到一个 403 未经授权的错误,我的 authorizationHeader 仍然为空。以上是关于如何使用身份验证管理器修复“错误凭据”错误?的主要内容,如果未能解决你的问题,请参考以下文章
身份验证失败 - grails spring security中的错误凭据
通过 Spring Security 的 Active Directory 身份验证返回由 LDAP 引起的有效用户的错误凭据:错误代码 49