package com.qiaoba.auth.config;

import com.qiaoba.auth.constants.SecurityConstant;
import com.qiaoba.auth.filters.AuthenticationCoreFilter;
import com.qiaoba.auth.handler.AccessDeniedHandler;
import com.qiaoba.auth.handler.LogoutHandler;
import com.qiaoba.auth.properties.AuthConfigProperties;
import com.qiaoba.common.base.constants.BaseConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;

/**
 * SpringSecurity安全配置
 *
 * @author ailanyin
 * @version 1.0
 * @since 2023/5/15 11:23
 */
@Configuration
@RequiredArgsConstructor
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class SpringSecurityConfig {

    private final AuthConfigProperties authConfigProperties;
    private final AccessDeniedHandler accessDeniedHandler;
    private final AuthenticationCoreFilter authenticationCoreFilter;
    private final LogoutHandler logoutHandler;


    @Bean
    SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();
        //白名单
        for (String url : authConfigProperties.getWhitelist()) {
            registry.antMatchers(url).permitAll();
        }
        // 文件资源 无需鉴权
        registry.antMatchers(BaseConstant.RESOURCE_PREFIX + "/**").permitAll();
        // 由于使用的是JWT，我们这里不需要csrf
        httpSecurity.csrf()
                .disable()
                //添加自定义未授权和未登录结果返回
                .exceptionHandling()
                .authenticationEntryPoint(accessDeniedHandler)
                .and()
                // 基于token，所以不需要session
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                //跨域请求会先进行一次options请求
                .antMatchers(HttpMethod.OPTIONS)
                .permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest()
                .authenticated();
        // 禁用缓存
        httpSecurity.headers().cacheControl();
        // 退出处理
        httpSecurity.logout().logoutUrl(SecurityConstant.LOGOUT_URI).logoutSuccessHandler(logoutHandler);
        // 添加JWT filter
        httpSecurity.addFilterBefore(authenticationCoreFilter, UsernamePasswordAuthenticationFilter.class);
        httpSecurity.addFilterBefore(authenticationCoreFilter, LogoutFilter.class);
        return httpSecurity.build();
    }
}
