zoukankan      html  css  js  c++  java
  • Spring Security 多登录接口实现

    需要先增加一个自定义的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();
         //主要通过这个token来决定使用哪个userDetailService.
         //UserDetailsAuthenticationProvider里面有个supports方法,主要用来验证指定的token是否符合.
         //可以通过指定不同类型的token来决定使用哪个userDetailService. 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);
        }
    }
  • 相关阅读:
    用Ext.override重写控件属性
    如何设置DateField的默认值
    ExtJs中获得当前选中行号(Grid中多选或者是单选)及Grid的反选(取消选中行)
    Ext.form各类控件的配置及方法
    犀利的系统验收工作
    UML系列 (五) 为什么要用UML建模之建模的重要性
    牛腩新闻发布系统(2)使用存储过程查询表
    如何编写优质的需求文档
    SCM软件配置管理 (一)SVN 与 CVS
    牛腩新闻发布系统 (3) 存过过程或函数""需要""参数,但未提供该参数
  • 原文地址:https://www.cnblogs.com/cearnach/p/9094227.html
Copyright © 2011-2022 走看看