我能够在Spring Boot应用程序中使用Spring Security登录。然后输入了错误的凭据,访问拒绝页面按预期方式工作。之后,我尝试使用正确的凭据登录,但是访问拒绝页面始终加载。解释解决方案?
WebSecurityConfig.java
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/showReg", "/", "/index.html", "/registerUser", "/login", "/showLogin", "/login/*")
.permitAll()
.anyRequest()
.authenticated();
http
.csrf().disable()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/showLogin")
.deleteCookies("remember-me").permitAll()
.and()
.rememberMe();
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
SecutityServiceImpl.java
import org.springframework.security.authentication.AuthenticationManager;
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.stereotype.Service;
@Service
public class SecurityServiceImpl implements SecurityService {
@Autowired
UserDetailsService userDetailsService;
@Autowired
AuthenticationManager authenticationManager;
@Override
public boolean login(String userName, String password) {
UserDetails userDetails = userDetailsService.loadUserByUsername(userName);
UsernamePasswordAuthenticationToken token=new UsernamePasswordAuthenticationToken(
userDetails,password,userDetails.getAuthorities());
authenticationManager.authenticate(token);
boolean result = token.isAuthenticated();
if (result){
SecurityContextHolder.getContext().setAuthentication(token);
}
return result;
}
}
答案 0 :(得分:1)
在尝试找出拒绝访问页面的原因之前, 具有3个参数构造函数的UsernamePasswordAuthenticationToken始终将身份验证标志设置为true。
UsernamePasswordAuthenticationToken token=new UsernamePasswordAuthenticationToken(
userDetails,password,userDetails.getAuthorities());
因此请检查认证结果是否为true,这不是您在if(result){...}
中所依赖的基于认证的真实状态:
boolean result = token.isAuthenticated();<- always true
对于尝试认证authenticationManager.authenticate(token);
令牌的尝试,此处应表示由用户凭据构造的身份验证对象,如下所示:
UsernamePasswordAuthenticationToken token=new UsernamePasswordAuthenticationToken(enteredUserName,enteredPassword);
传递给身份验证管理器,后者依次委托注册的身份验证提供程序进行身份验证。 我认为您的SecurityServiceImpl模仿了身份验证提供程序逻辑。我建议将该逻辑带到AuthenticationProvider实现中,并在AuthenticationManagerBuilder中注册它。 基本示例:
@Component
public class AuthProvider implements AuthenticationProvider {
@Autowired
UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String enteredUserName = authentication.getName();
String enteredPassword = authentication.getCredentials().toString();
UserDetails ud = userDetailsService.loadUserByUsername(userName);
// compare/check password
// if password valid
return new UsernamePasswordAuthenticationToken(ud,null,authorities);
}
@Override
public boolean supports(Class<?> aClass) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass);
}
}