SpringBoot整合SpringSecurity,SESSION 并发管理,同账号只允许登录一次

来源:互联网 发布:天池大数据竞赛 个人 编辑:程序博客网 时间:2024/05/17 21:55

重写了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;    
阅读全文
0 0
原创粉丝点击