package com.zhgd.xmgl.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @program: devManage
 * @description:
 * @author: Mr.Peng
 * @create: 2019-09-24 11:35
 **/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final JwtAuthenticationEntryPoint unauthorizedHandler;

    private final AccessDeniedHandler accessDeniedHandler;

    private final UserDetailsService CustomUserDetailsService;

    private final JwtTokenFilter authenticationTokenFilter;

    @Value("${security.enable}")
    private boolean securityEnable;

    @Autowired
    public WebSecurityConfig(JwtAuthenticationEntryPoint unauthorizedHandler,
                             @Qualifier("RestAuthenticationAccessDeniedHandler") AccessDeniedHandler accessDeniedHandler,
                             @Qualifier("CustomUserDetailsService") UserDetailsService CustomUserDetailsService,
                             JwtTokenFilter authenticationTokenFilter) {
        this.unauthorizedHandler = unauthorizedHandler;
        this.accessDeniedHandler = accessDeniedHandler;
        this.CustomUserDetailsService = CustomUserDetailsService;
        this.authenticationTokenFilter = authenticationTokenFilter;
    }

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder
                // 设置UserDetailsService
                .userDetailsService(this.CustomUserDetailsService)
                // 使用BCrypt进行密码的hash
                .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().disable();
        if (securityEnable) {
            http.authorizeRequests()
                    //请求路径允许访问
                    .antMatchers("/xmgl/api/**").permitAll()
                    .antMatchers("/license/**").permitAll()
                    .antMatchers("/api/main/alarm").permitAll()
                    .antMatchers("/xmgl/lifter/list").permitAll()
                    .antMatchers("/xmgl/systemUser/login").permitAll()
                    .antMatchers("/xmgl/file/preview").permitAll()
                    .antMatchers("/xmgl/government/list").permitAll()
                    .antMatchers("/ent/enterprise/add").permitAll()
                    .antMatchers("/project/project/add").permitAll()
                    .antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
                    .anyRequest().authenticated()       // 剩下所有的验证都需要验证
                    .and()
                    // 禁用 Spring Security 自带的跨域处理
                    .csrf().disable()
                    // 授权异常
                    .exceptionHandling()
                    .authenticationEntryPoint(unauthorizedHandler)
                    //.authenticationEntryPoint()
                    .accessDeniedHandler(accessDeniedHandler)
                    .and()
                    // 定制我们自己的 session 策略：调整为让 Spring Security 不创建和使用 session
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            //以下这句就可以控制单个用户只能创建一个session，也就只能在服务器登录一次
            //http.sessionManagement().maximumSessions(1).expiredUrl("/login");

            // Apply JWT
            //http.apply(new JwtTokenFilterConfigurer(jwtTokenProvider));
            // 添加JWT filter
            http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        } else {
            http.csrf().disable()
                    .authorizeRequests()
                    .anyRequest().permitAll()
                    .and().logout().permitAll();
        }
    }
    public  void getStartDate(){
        // 二分查找

    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // Allow swagger to be accessed without authentication
        web.ignoring()
                //忽略任何以什么开头的请求
                .antMatchers("/v2/api-docs")
                .antMatchers("/swagger-resources/**")
                .antMatchers("/swagger-ui.html")
                .antMatchers("/configuration/**")
                .antMatchers("/webjars/**")
                .antMatchers("/public")
                .antMatchers("/doc.html")
                .antMatchers("/static/document/README.md")
                .antMatchers("/index.html")
                .antMatchers("/equipmentCenter.html")
                .antMatchers("/equipmentCenter.html/**")
                .antMatchers("/js/**")
                .antMatchers("/img/**")
                .antMatchers("/fonts/**")
                .antMatchers("/css/**")
                .antMatchers("/document/**")
                .antMatchers("/doc/**")
                .antMatchers("/video/**")
                .antMatchers("/animate/**")
                .antMatchers("/static/**")
                .antMatchers("/flowable/**")
                .antMatchers("/favicon.ico")
                .antMatchers("/favicon.png")
                // Un-secure H2 Database (for testing purposes, H2 console shouldn't be unprotected in production)
                .and()
                .ignoring()
                .antMatchers("/h2-console/**/**");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(12);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
