org.springframework.security.authentication.BadCredentialsException: The present

本文详细介绍了如何使用 Spring Security 进行 HTTP 配置,并解决 Remember Me 功能出现的认证异常问题。包括自定义 RememberMeService 和配置相关组件,最终通过在 RememberMeBean 上添加 key 属性解决了认证失败的问题。
  • spring security http配置
<http auto-config="true" use-expressions="true">
        <intercept-url pattern="/css/**" access="permitAll"/>
        <intercept-url pattern="/fonts/**" access="permitAll"/>
        <intercept-url pattern="/js/**" access="permitAll"/>
        <intercept-url pattern="/signup.html*" access="permitAll"/>
        <intercept-url pattern="/login.html*" access="permitAll"/>
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>

        <remember-me services-ref="enhancedTokenRememberMeServices"/>
        <form-login login-page="/login.html" default-target-url="/home.html" login-processing-url="/login"
                    username-parameter="username" password-parameter="password"/>
        <logout invalidate-session="true" logout-url="/logout" logout-success-url="/"/>
    </http>
  •  自定义remember me service
    <beans:bean id="enhancedPersistentTokenBasedRememberMeServices" class="com.aasonwu.mycompany.EnhancedPersistentTokenBasedRememberMeServices">
            <beans:constructor-arg type="java.lang.String"
                                   value="BoSk70Yar38~veg91DoCKs=sLaIn!metE55bURgs71rug;ILEa=Ikon79sept+ree$Fuel99baKER;wOe43JackS=TinS79babA73tiLmibs10bIsE*"/>
            <beans:constructor-arg type="org.springframework.security.core.userdetails.UserDetailsService"
                                   ref="userDao"/>
            <beans:constructor-arg type="org.springframework.security.web.authentication.rememberme.PersistentTokenRepository"
                                   ref="jdbcTokenRepository" />
            <beans:property name="cookieName" value="MYCOMPANY_REMEMBER_ME"/>
            <beans:property name="parameter" value="remember_me"/>
        </beans:bean>
     
  • 运行时遇到出错
    org.springframework.security.authentication.BadCredentialsException: The presented RememberMeAuthenticationToken does not contain the expected key
    	at org.springframework.security.authentication.RememberMeAuthenticationProvider.authenticate(RememberMeAuthenticationProvider.java:64) ~[RememberMeAuthenticationProvider.class:3.2.2.RELEASE]
    	at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156) ~[ProviderManager.class:3.2.2.RELEASE]
    	at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:102) ~[RememberMeAuthenticationFilter.class:3.2.2.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [FilterChainProxy$VirtualFilterChain.class:3.2.2.RELEASE]
    	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154) [SecurityContextHolderAwareRequestFilter.class:3.2.2.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [FilterChainProxy$VirtualFilterChain.class:3.2.2.RELEASE]
    	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) [RequestCacheAwareFilter.class:3.2.2.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [FilterChainProxy$VirtualFilterChain.class:3.2.2.RELEASE]
    	at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150) [BasicAuthenticationFilter.class:3.2.2.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [FilterChainProxy$VirtualFilterChain.class:3.2.2.RELEASE]
    	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) [AbstractAuthenticationProcessingFilter.class:3.2.2.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [FilterChainProxy$VirtualFilterChain.class:3.2.2.RELEASE]
    	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) [LogoutFilter.class:3.2.2.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [FilterChainProxy$VirtualFilterChain.class:3.2.2.RELEASE]
    	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) [WebAsyncManagerIntegrationFilter.class:3.2.2.RELEASE]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108) [OncePerRequestFilter.class:4.0.2.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [FilterChainProxy$VirtualFilterChain.class:3.2.2.RELEASE]
    	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) [SecurityContextPersistenceFilter.class:3.2.2.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [FilterChainProxy$VirtualFilterChain.class:3.2.2.RELEASE]
    	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) [FilterChainProxy.class:3.2.2.RELEASE]
    	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) [FilterChainProxy.class:3.2.2.RELEASE]
    	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) [DelegatingFilterProxy.class:4.0.2.RELEASE]
    	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) [DelegatingFilterProxy.class:4.0.2.RELEASE]
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:8.0.0-RC10]
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:8.0.0-RC10]
    	at com.opensymphony.sitemesh.webapp.SiteMeshFilter.obtainContent(SiteMeshFilter.java:129) [SiteMeshFilter.class:na]
    	at com.opensymphony.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:77) [SiteMeshFilter.class:na]
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:8.0.0-RC10]
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:8.0.0-RC10]
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:221) [catalina.jar:8.0.0-RC10]
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:107) [catalina.jar:8.0.0-RC10]
    	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504) [catalina.jar:8.0.0-RC10]
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [catalina.jar:8.0.0-RC10]
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:76) [catalina.jar:8.0.0-RC10]
    	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:934) [catalina.jar:8.0.0-RC10]
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:90) [catalina.jar:8.0.0-RC10]
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522) [catalina.jar:8.0.0-RC10]
    	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1015) [tomcat-coyote.jar:8.0.0-RC10]
    	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:646) [tomcat-coyote.jar:8.0.0-RC10]
    	at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:277) [tomcat-coyote.jar:8.0.0-RC10]
    	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2451) [tomcat-coyote.jar:8.0.0-RC10]
    	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2440) [tomcat-coyote.jar:8.0.0-RC10]
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_51]
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_51]
    	at java.lang.Thread.run(Thread.java:744) [na:1.7.0_51]
    60123 [http-apr-8080-exec-1] DEBUG c.a.m.EnhancedTokenRememberMeServices - Interactive login attempt was unsuccessful.
    60123 [http-apr-8080-exec-1] DEBUG c.a.m.EnhancedTokenRememberMeServices - Cancelling cookie
     
  • 解决问题方案。在remember-me 标签上添加key属性,与remember-me bean中的key相同,即可
    <remember-me services-ref="enhancedTokenRememberMeServices"
                         key="BoSk70Yar38~veg91DoCKs=sLaIn!metE55bURgs71rug;ILEa=Ikon79sept+ree$Fuel99baKER;wOe43JackS=TinS79babA73tiLmibs10bIsE*"/>
     
package cn.njucm.dosepre.service; import cn.njucm.dosepre.dto.LoginRequest; import cn.njucm.dosepre.dto.RegisterRequest; import cn.njucm.dosepre.entity.User; import cn.njucm.dosepre.repository.UserRepository; import cn.njucm.dosepre.util.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @Service // 关键!必须加 @Service 注解才能被注入 public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder; // 用于加密密码 @Autowired private JwtUtil jwtUtil; @Override public void registerDoctor(RegisterRequest request) { if (userRepository.findByUsername(request.getUsername()).isPresent()) { throw new IllegalArgumentException("用户名已存在"); } User user = new User(); user.setUsername(request.getUsername()); user.setPassword(passwordEncoder.encode(request.getPassword())); user.setRole("ROLE_DOCTOR"); // 默认角色 user.setStatus("PENDING"); // 待审核 userRepository.save(user); } @Override public String login(String username, String password) { User user = userRepository.findByUsername(username) .orElseThrow(() -> new BadCredentialsException("用户名或密码错误")); if (!passwordEncoder.matches(password, user.getPassword())) { throw new BadCredentialsException("用户名或密码错误"); } if (!"APPROVED".equals(user.getStatus())) { throw new BadCredentialsException("账户尚未通过审核"); } // 生成 JWT Token return jwtUtil.generateToken(username); } } Cannot resolve symbol 'UserRepository' Cannot resolve symbol 'UserService' Could not autowire. No beans of 'UserRepository' type found. Could not autowire. No beans of 'PasswordEncoder' type found.
最新发布
11-19
package com.drawingapp.service; import com.drawingapp.dto.ApiResponse; import com.drawingapp.dto.LoginRequest; import com.drawingapp.dto.RegisterRequest; import com.drawingapp.entity.User; import com.drawingapp.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; @Service @RequiredArgsConstructor public class UserServiceImpl implements UserService, UserDetailsService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; private final JwtService jwtService; private final AuthenticationManager authenticationManager; @Override public ResponseEntity<ApiResponse<?>> login(LoginRequest request) { try { authenticationManager.authenticate( new UsernamePasswordAuthenticationToken( request.getUsername(), request.getPassword() ) ); var user = userRepository.findByUsername(request.getUsername()) .orElseThrow(() -> new UsernameNotFoundException("用户不存在")); var jwtToken = jwtService.generateToken((UserDetails) user); Map<String, Object> responseData = new HashMap<>(); responseData.put("token", jwtToken); // responseData.put("user", Map.of( // "id", user.getId(), // "username", user.getUsername(), // "email", user.getEmail() // )); Map<String, Object> userMap = new HashMap<>(); userMap.put("id", user.getId()); userMap.put("username", user.getUsername()); userMap.put("email", user.getEmail()); responseData.put("user", userMap); return ResponseEntity.ok(ApiResponse.success(responseData)); } catch (Exception e) { return ResponseEntity.status(401) .body(ApiResponse.error(401, "用户名或密码错误")); } } @Override public ResponseEntity<ApiResponse<?>> register(RegisterRequest request) { if (userRepository.existsByUsername(request.getUsername())) { return ResponseEntity.badRequest() .body(ApiResponse.error(400, "用户名已存在")); } if (request.getEmail() != null && userRepository.existsByEmail(request.getEmail())) { return ResponseEntity.badRequest() .body(ApiResponse.error(400, "邮箱已存在")); } // var user = User.builder() // .username(request.getUsername()) // .passwordHash(passwordEncoder.encode(request.getPassword())) // .email(request.getEmail()) // .build(); // // userRepository.save(user); User user = new User(); user.setUsername(request.getUsername()); user.setPasswordHash(passwordEncoder.encode(request.getPassword())); user.setEmail(request.getEmail()); userRepository.save(user); return ResponseEntity.status(201) .body(ApiResponse.success("用户注册成功", null)); } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return (UserDetails) userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("用户不存在")); } } 修改整页,我要结果直接能复制粘贴的
09-23
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值