package com.tykj.dev.device.user.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tykj.dev.device.user.config.handler.MyFailHandler;
import com.tykj.dev.device.user.config.handler.MyLogoutHandler;
import com.tykj.dev.device.user.config.handler.MySuccessHandler;
import com.tykj.dev.device.user.config.url.ApiResult;
import com.tykj.dev.device.user.config.url.UrlAccessDecisionManager;
import com.tykj.dev.device.user.config.url.UrlAccessDeniedHandler;
import com.tykj.dev.device.user.config.url.UrlFilterInvocationSecurityMetadataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * @author zjm
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyEntryPoint myEntryPoint;

    @Autowired
    private MyUserDetailsServiceImpl myUserDetailsServiceImpl;

    @Autowired
    private MyLogoutHandler myLogoutHandler;

    @Autowired
    private MyFailHandler failHandler;

    @Autowired
    private MySuccessHandler successHandler;

    /**
     * 获取访问url所需要的角色信息
     */
    @Autowired
    private UrlFilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource;
    /**
     * 认证权限处理 - 将上面所获得角色权限与当前登录用户的角色做对比，如果包含其中一个角色即可正常访问
     */
    @Autowired
    private UrlAccessDecisionManager urlAccessDecisionManager;
    /**
     * 自定义访问无权限接口时403响应内容
     */
    @Autowired
    private UrlAccessDeniedHandler urlAccessDeniedHandler;

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {

        httpSecurity
                .cors().and()
                .authorizeRequests()
//                .antMatchers("/user/userLogout").permitAll()permitAll
//                .antMatchers("/**").permitAll()

                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        o.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource);
                        o.setAccessDecisionManager(urlAccessDecisionManager);
                        return o;
                    }
                })
                .and()
                .formLogin()
                .loginProcessingUrl("/userLogin")
                .permitAll()
//                .failureHandler(failHandler)
//                .successHandler(successHandler)
//                .permitAll()
                .and()
                .logout()
                .logoutUrl("/userLogout")
                .logoutSuccessHandler(myLogoutHandler)
                .deleteCookies("JESSIONID")
//                .permitAll()
                .and()
                .exceptionHandling()
                .accessDeniedHandler(urlAccessDeniedHandler)
                .authenticationEntryPoint(myEntryPoint)
//                .accessDeniedHandler(accessHandler)
                .and()
                .addFilterAt(new ConcurrentSessionFilter(sessionRegistry(), event -> {
                HttpServletResponse resp = event.getResponse();
                resp.setContentType("application/json;charset=utf-8");
                resp.setStatus(401);
                PrintWriter out = resp.getWriter();
                out.write(new ObjectMapper().writeValueAsString(ApiResult.build(405,"您已在另一台设备登录，本次登录已下线!")));
                out.flush();
                out.close();
                }), ConcurrentSessionFilter.class)
                .addFilterAt(myFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(corsFilter(), ChannelProcessingFilter.class)
//                .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).disable().sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(false).expiredUrl("/userLogout").sessionRegistry(sessionRegistry());
//                .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).disable();
                .csrf().disable();
//                 httpSecurity.headers().cacheControl();

    }

    @Override
    public void configure(WebSecurity web){
        //swagger静态资源访问
        web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/security", "/swagger-ui.html", "/webjars/**","/swagger-resources/configuration/ui","**/swagge‌​r-ui.html","/static/**");
    }

    @Bean
    public MyFilter myFilter() throws Exception {
        MyFilter filter = new MyFilter();
        filter.setAuthenticationSuccessHandler(successHandler);
        filter.setAuthenticationFailureHandler(failHandler);
        filter.setFilterProcessesUrl("/userLogin");
        filter.setAuthenticationManager(this.authenticationManager());
//        filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/userLogin", "POST"));
        ConcurrentSessionControlAuthenticationStrategy sessionStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
        sessionStrategy.setMaximumSessions(1);
        filter.setSessionAuthenticationStrategy(sessionStrategy);
        return filter;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsServiceImpl);
    }

    @Bean
    HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
    @Bean
    public SessionRegistryImpl sessionRegistry(){
        return new SessionRegistryImpl();
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }


}
