Spring Security 多登錄實現
阿新 • • 發佈:2018-05-26
技術分享 entity else getc auto 驗證過 編寫 IE over
需要先增加一個自定義的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); } }
Spring Security 多登錄實現