zoukankan      html  css  js  c++  java
  • SpringBoot整合SpringSecurity,SESSION 并发管理,同账号只允许登录一次

    重写了UsernamePasswordAuthenticationFilter,里面继承AbstractAuthenticationProcessingFilter,这个类里面的session认证策略,是一个空方法,貌似RememberMe也是.

    public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean implements ApplicationEventPublisherAware, MessageSourceAware {
        protected ApplicationEventPublisher eventPublisher;
        protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
        private AuthenticationManager authenticationManager;
        protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
        private RememberMeServices rememberMeServices = new NullRememberMeServices();
        private RequestMatcher requiresAuthenticationRequestMatcher;
        private boolean continueChainBeforeSuccessfulAuthentication = false;
        private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();
        private boolean allowSessionCreation = true;
        private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
        private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
    NullAuthenticatedSessionStrategy 源码
    public final class NullAuthenticatedSessionStrategy implements SessionAuthenticationStrategy {
        public NullAuthenticatedSessionStrategy() {
        }
    
        public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
        }
    }

    所以必须自己配置一个session验证策略,以及配置并发控制.红字为关键

    WebSecurityConfigurerAdapter 
    /**
     * Created by ZhenWeiLai on on 2016-10-16.
     * <p>
     * 三种方法级权限控制
     * <p>
     * 1.securedEnabled: Spring Security’s native annotation
     * 2.jsr250Enabled: standards-based and allow simple role-based constraints
     * 3.prePostEnabled: expression-based
     */
    @EnableWebSecurity
    //@EnableGlobalMethodSecurity(prePostEnabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Resource
        private UserDetailsService userDetailsService;
    
        @Resource
        private FilterInvocationSecurityMetadataSource securityMetadataSource;
    
        @Resource
        private SessionRegistry sessionRegistry;
    
        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/assets/**");
            web.ignoring().antMatchers("/components/**");
            web.ignoring().antMatchers("/css/**");
            web.ignoring().antMatchers("/images/**");
            web.ignoring().antMatchers("/js/**");
            web.ignoring().antMatchers("/mustache/**");
            web.ignoring().antMatchers("/favicon.ico");
    
            //注册地址不拦截
    //        web.ignoring().antMatchers("/base/invoice/userinfo/u/reg");
    
    //        web.ignoring().antMatchers("/**");
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            //解决不允许显示在iframe的问题
            http.headers().frameOptions().disable();
    
            http.addFilterAt(usernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
           //session并发控制过滤器
            http.addFilterAt(new ConcurrentSessionFilter(sessionRegistry,sessionInformationExpiredStrategy()),ConcurrentSessionFilter.class);
            //自定义过滤器
            //在适当的地方加入
            http.addFilterAt(filterSecurityInterceptor(securityMetadataSource, accessDecisionManager(), authenticationManagerBean()), FilterSecurityInterceptor.class);
    
            http.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")).and().logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll().and().exceptionHandling().accessDeniedPage("/accessDenied");
    
    
            http.authorizeRequests().anyRequest().fullyAuthenticated();
    
            // 关闭csrf
            http.csrf().disable();
    
    
            /**
             * 以下配置无效
             */
            //session管理
            //session失效后跳转
    //        http.sessionManagement().invalidSessionUrl("/login");
    //        //只允许一个用户登录,如果同一个账户两次登录,那么第一个账户将被踢下线,跳转到登录页面
    //        http.sessionManagement().maximumSessions(1).expiredUrl("/login");
        }
    
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth)
                throws Exception {
            // 自定义UserDetailsService,设置加密算法
            auth.userDetailsService(userDetailsService);
    //.passwordEncoder(passwordEncoder())
            //不删除凭据,以便记住用户
            auth.eraseCredentials(false);
        }
    
        //session失效跳转
        private SessionInformationExpiredStrategy sessionInformationExpiredStrategy() {
            return new SimpleRedirectSessionInformationExpiredStrategy("/login");
        }
    
        @Bean
        public SessionRegistry sessionRegistry() {
            return new SessionRegistryImpl();
        }
    
        //SpringSecurity内置的session监听器
        @Bean
        public HttpSessionEventPublisher httpSessionEventPublisher() {
            return new HttpSessionEventPublisher();
        }
    
        private UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() throws Exception {
            UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter = new CuzUsernamePasswordAuthenticationFilter();
            usernamePasswordAuthenticationFilter.setPostOnly(true);
            usernamePasswordAuthenticationFilter.setAuthenticationManager(this.authenticationManager());
            usernamePasswordAuthenticationFilter.setUsernameParameter("name_key");
            usernamePasswordAuthenticationFilter.setPasswordParameter("pwd_key");
            usernamePasswordAuthenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/checkLogin", "POST"));
            usernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(simpleUrlAuthenticationFailureHandler());
            usernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());
            //session并发控制,因为默认的并发控制方法是空方法.这里必须自己配置一个
            usernamePasswordAuthenticationFilter.setSessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry));
            return usernamePasswordAuthenticationFilter;
        }
    
    //    @Bean
    //    public LoggerListener loggerListener() {
    //        System.out.println("org.springframework.security.authentication.event.LoggerListener");
    //        return new LoggerListener();
    //    }
    //
    //    @Bean
    //    public org.springframework.security.access.event.LoggerListener eventLoggerListener() {
    //        System.out.println("org.springframework.security.access.event.LoggerListener");
    //        return new org.springframework.security.access.event.LoggerListener();
    //    }
    
        /**
         * 投票器
         */
        private AbstractAccessDecisionManager accessDecisionManager() {
            List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList();
            decisionVoters.add(new AuthenticatedVoter());
            decisionVoters.add(new RoleVoter());//角色投票器,默认前缀为ROLE_
            RoleVoter AuthVoter = new RoleVoter();
            AuthVoter.setRolePrefix("AUTH_");//特殊权限投票器,修改前缀为AUTH_
            decisionVoters.add(AuthVoter);
            AbstractAccessDecisionManager accessDecisionManager = new AffirmativeBased(decisionVoters);
            return accessDecisionManager;
        }
    
        @Override
        public AuthenticationManager authenticationManagerBean() {
            AuthenticationManager authenticationManager = null;
            try {
                authenticationManager = super.authenticationManagerBean();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return authenticationManager;
        }
    
    
        /**
         * 验证异常处理器
         *
         * @return
         */
        private SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler() {
            return new SimpleUrlAuthenticationFailureHandler("/getLoginError");
        }
    
    
    //    /**
    //     * 表达式控制器
    //     *
    //     * @return
    //     */
    //    private DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() {
    //        DefaultWebSecurityExpressionHandler webSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
    //        return webSecurityExpressionHandler;
    //    }
    
    //    /**
    //     * 表达式投票器
    //     *
    //     * @return
    //     */
    //    private WebExpressionVoter webExpressionVoter() {
    //        WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
    //        webExpressionVoter.setExpressionHandler(webSecurityExpressionHandler());
    //        return webExpressionVoter;
    //    }
    
        // Code5  官方推荐加密算法
    //    @Bean("passwordEncoder")
    //    public BCryptPasswordEncoder passwordEncoder() {
    //        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
    //        return bCryptPasswordEncoder;
    //    }
    
    //    // Code3----------------------------------------------
    
    
        /**
         * 登录成功后跳转
         * 如果需要根据不同的角色做不同的跳转处理,那么继承AuthenticationSuccessHandler重写方法
         *
         * @return
         */
        private SimpleUrlAuthenticationSuccessHandler authenticationSuccessHandler() {
            return new SimpleUrlAuthenticationSuccessHandler("/loginSuccess");
        }
    
    
        /**
         * Created by ZhenWeiLai on on 2016-10-16.
         */
    
        private FilterSecurityInterceptor filterSecurityInterceptor(FilterInvocationSecurityMetadataSource securityMetadataSource, AccessDecisionManager accessDecisionManager, AuthenticationManager authenticationManager) {
            FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
            filterSecurityInterceptor.setSecurityMetadataSource(securityMetadataSource);
            filterSecurityInterceptor.setAccessDecisionManager(accessDecisionManager);
            filterSecurityInterceptor.setAuthenticationManager(authenticationManager);
            return filterSecurityInterceptor;
        }
    
    
    }

    继承UsernamePasswordAuthenticationFilter ,注入SessionRegistry ,当用户登录验证成功后注册session

    /**
     * Created by ZhenWeiLai on 2017/6/2.
     */
    public class CuzUsernamePasswordAuthenticationFilter  extends UsernamePasswordAuthenticationFilter {
    
        private boolean postOnly = true;
    
        @Resource
        private SessionRegistry sessionRegistry;
    
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            if(this.postOnly && !request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            } else {
                String username = this.obtainUsername(request);
                String password = this.obtainPassword(request);
                if(username == null) {
                    username = "";
                }
    
                if(password == null) {
                    password = "";
                }
    
                username = username.trim();
                UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
                //用户名密码验证通过后,注册session
                sessionRegistry.registerNewSession(request.getSession().getId(),authRequest.getPrincipal());
                this.setDetails(request, authRequest);
                return this.getAuthenticationManager().authenticate(authRequest);
            }
        }
    }

    重写用户实体类的比较方法.

        /**
         * 重写比较方法,SpringSecurity根据用户名来比较是否同一个用户
         */
        @Override
        public boolean equals(Object o){
            if(o.toString().equals(this.username))
                return true;
            return false;
        }
    
        @Override
        public int hashCode(){
            return username.hashCode();
        }
    
    
        @Override
        public String toString() {
            return this.username;
        }
  • 相关阅读:
    IL查看泛型
    IL查看委托
    IL查看override
    为VS集成IL环境
    HashTable Dictionary HashMap
    C#集合类
    Resharper团队协作之TODO
    怪物彈珠Monster Strike 攻略
    [Editor]Unity Editor类常用方法
    C# Reflection BindingFlags
  • 原文地址:https://www.cnblogs.com/sweetchildomine/p/6932488.html
Copyright © 2011-2022 走看看