需要先增加一个自定义的Filter去继承 UsernamePasswordAuthenticationFilter 或者 AbstractAuthenticationProcessingFilter
然后在自定义的Filter里面指定登录的Url . 设置过滤器的时候,必须为过滤器指定一个 authenticationManager ,并且初始化构造函数的时候,要传入该manager.
再编写一个Provider , 把自定义的UserDetailService传给该provider.
具体实现过程如下:
添加配置:
@Override
protected void configure(AuthenticationManagerBuilder auth) {
//增加自定义的UserDetailService
userDetailsAuthenticationProvider.setUserDetailsService(userDetailsService);
//设置一个Provider
auth.authenticationProvider(userDetailsAuthenticationProvider);
}
关键配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
//手动实现的权限验证管理器
movieAuthorizeConfigProviderManager.configure(http.authorizeRequests());
//添加前台登录验证过滤器与userDetailService,不同的登录处理URL需要在Filter里面指定
UserAuthenticationFilter userAuthenticationFilter = new UserAuthenticationFilter();
//每个Filter必须指定一个authenticationManager
userAuthenticationFilter.setAuthenticationManager(authenticationManager());
//设置登录成功处理事件
userAuthenticationFilter.setAuthenticationSuccessHandler(movieAuthenticationSuccessHandler);
//设置登录失败处理事件
userAuthenticationFilter.setAuthenticationFailureHandler(movieAuthenticationFailureHandler);
http.addFilterBefore(userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
完整配置:

自定义过滤器:
public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public static final String POST = "POST";
public MyAuthenticationFilter() {
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/user/login/check", "POST"));
this.setAuthenticationManager(getAuthenticationManager());
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!request.getMethod().equals(POST)) {
throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
}
Provider:
@Component
public class UserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
private volatile String userNotFoundEncodedPassword;
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
@Autowired
private PasswordEncoder passwordEncoder;
private UserDetailsService userDetailsService;
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
if (authentication.getCredentials() == null) {
throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
prepareTimingAttackProtection();
try {
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException( "UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
} catch (UsernameNotFoundException ex) {
mitigateAgainstTimingAttack(authentication);
throw ex;
} catch (InternalAuthenticationServiceException ex) {
throw ex;
} catch (Exception ex) {
throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
}
}
private void prepareTimingAttackProtection() {
if (this.userNotFoundEncodedPassword == null) {
this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD);
}
}
private void mitigateAgainstTimingAttack(UsernamePasswordAuthenticationToken authentication) {
if (authentication.getCredentials() != null) {
String presentedPassword = authentication.getCredentials().toString();
this.passwordEncoder.matches(presentedPassword, this.userNotFoundEncodedPassword);
}
}
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
UserDetailService:
@Component
@Slf4j
@Qualifier("normalUserDetailService")
public class UserDetailServiceImpl implements UserDetailsService {
private final IUserDao userDao;
public UserDetailServiceImpl(IUserDao userDao) {
this.userDao = userDao;
}
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
club.cearnach.movie.entity.User user = userDao.findByAccount(username)
.orElseThrow(() -> new UsernameNotFoundException("找不到指定的用户"));
List<GrantedAuthority> authorities = AuthorityUtils
.commaSeparatedStringToAuthorityList(
MovieSecurityConstants.ROLE_PREFIX.concat(user.getRole().getName()));
return new User(user.getAccount(), user.getPassword(), authorities);
}
}
第二个UserDetailService的实现:
@Component
@Qualifier("adminDetailService")
public class AdminUserDetailServiceImpl implements UserDetailsService {
private final IAdminService adminService;
public AdminUserDetailServiceImpl(IAdminService adminService) {
this.adminService = adminService;
}
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Admin admin = adminService.findByAccount(username)
.orElseThrow(() -> new UsernameNotFoundException(AdminException.ADMIN_CAN_NOT_FOUNT));
List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(
MovieSecurityConstants.ROLE_PREFIX.concat(admin.getRole().getName()));
return new User(admin.getAccount(), admin.getPassword(), authorities);
}
}
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/7482.html