package cn.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import cn.security.spring.crypto.PasswordEncoderUtil;
import cn.service.auth.AuthenticationEntryPointImpl;
import cn.service.auth.UserAccessDeniedHandlerImpl;
import cn.service.token.JwtAuthTokenFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.firewall.DefaultHttpFirewall;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig {
    //确定
    @Value("${sam.sys.encoder}")
    private String encoder;

    //认证失败处理
    @Autowired
    AuthenticationEntryPointImpl unauthorizedHandler;

    //权限拒绝处理逻辑
    @Autowired
    UserAccessDeniedHandlerImpl accessDeniedHandler;

    //token认证过滤器
    @Autowired
    private JwtAuthTokenFilter authenticationTokenFilter;

    @Bean
    public PasswordEncoderUtil passwordEncoder() {
        return new PasswordEncoderUtil(encoder);
    }

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedMethods("*");
            }
        };
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers(
                        "/index", "/validateCode", "/authenticate","/Home/**", "/Home","/logout"
                        ,"/api/facade/login","/api/facade/captchaImage","/api/file/**"
                        , "/audio/**","/archive/**","/avatar/**","/news/**" //临时为VUE开辟的权限
                        , "/app/**", "/atv/**", "/websocket/**"  //websocket排除,
						, "/api/**"
                ).permitAll()
                .anyRequest().authenticated();//除上面外的所有请求全部需要鉴权认证
         http.headers().frameOptions().sameOrigin();
        http.rememberMe()
                //允许cookie，参数为cookie有效期(两周) 单位：秒
                .tokenValiditySeconds(1209600);
        http.exceptionHandling()
                //用来解决认证过的用户访问无权限资源时的异常
                .accessDeniedHandler(accessDeniedHandler)
                //用来解决匿名用户访问无权限资源时的异常
                .authenticationEntryPoint(unauthorizedHandler)
        ;

        /**使用自定义的 Token过滤器 验证请求的Token是否合法*/
        http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        //CRSF禁用，不使用session
        http.csrf().disable();
        /**禁用session、启用token即 Spring Security won't create a session*/
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        return http.build();
    }

    /**
     * Spring Security will automatically pick up the UserDetailsService and PasswordEncoder beans.
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    /**
     * HTTP 防火墙规则修改：允许URL包含双斜杠
     *
     * @return
     */
    @Bean
    public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
        return new DefaultHttpFirewall();
    }
}