package com.philisense.www.config;

import com.philisense.www.common.config.CommonConst;
import com.philisense.www.constant.Constants;
import com.philisense.www.handler.*;
import com.philisense.www.filter.JwtAuthorizationTokenFilter;
import com.philisense.www.service.JwtUserDetailsService;
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.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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.http.SessionCreationPolicy;

import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.filter.CorsFilter;

/**
 * spring security配置
 *
 * @author
 */
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    @Qualifier("jwtUserDetailsService")
    private JwtUserDetailsService jwtUserDetailsService;

    /**
     * 自定义强散列哈希加密实现
     */
    @Autowired
    private PasswordEncoderConfig passwordEncoderConfig;

    /**
     * 认证失败处理类
     */
    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    /**
     * 认证失败处理类
     */
    @Autowired
    private JwtAccessDeniedHandler jwtAccessDeniedHandler;

    /**
     * 退出处理类
     */
    @Autowired
    private JwtLogoutSuccessHandler jwtLogoutSuccessHandler;

    /**
     * 自定义基于JWT的安全过滤器
     */
    @Autowired
    private JwtAuthorizationTokenFilter jwtAuthorizationTokenFilter;

    /**
     * 跨域过滤器
     */
    @Autowired
    private CorsFilter corsFilter;

    /**
     * 登录授权路径
     */
    @Value("${jwt.auth.path}")
    private String loginPath;

    /**
     * 退出授权路径
     */
    @Value("${jwt.auth.logout}")
    private String logout;

    /**
     * 身份认证接口
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                //用户认证处理
                .userDetailsService(jwtUserDetailsService)
                //密码处理
                .passwordEncoder(passwordEncoderConfig.bCryptPasswordEncoder());
    }

    @Bean
    public GrantedAuthorityDefaults grantedAuthorityDefaults() {
        // Remove the ROLE_ prefix 保留默认前缀
        return new GrantedAuthorityDefaults("ROLE_");
    }

    /**
     * 解决 无法直接注入 AuthenticationManager
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    /**
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问（非remember-me下自动登录）
     * hasAnyAuthority     |   如果有参数，参数表示权限，则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数，参数表示角色，则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数，参数表示权限，则其权限可以访问
     * hasIpAddress        |   如果有参数，参数表示IP地址，如果用户IP和参数匹配，则可以访问
     * hasRole             |   如果有参数，参数表示角色，则其角色可以访问
     * permitAll           |   用户可以任意访问
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                // 开启跨域 cors()
                .cors().and()
                // CSRF禁用，因为不使用session
                .csrf().disable()
                // 授权异常 (认证失败处理类)
                .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and()
                // 资源权限
                .exceptionHandling().accessDeniedHandler(jwtAccessDeniedHandler).and()

                // 不创建会话，基于token，所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

                // 过滤请求
                .authorizeRequests()
                // 处理跨域请求中的Preflight请求
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .antMatchers(
                        HttpMethod.GET,
                        "/",
                        "/*.html",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js"
                ).permitAll()
                // 对于登录login 等允许访问
                .antMatchers(HttpMethod.POST,  CommonConst.WEB_REST_SERVICE_PREFICX + "auth" + loginPath).permitAll()
                .antMatchers(HttpMethod.POST, CommonConst.APP_REST_SERVICE_PREFICX + "auth" + loginPath).permitAll()
                // 注册功能允许访问
                .antMatchers("/web/api/service/user/register/**").permitAll()
                // swagger start
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/*/api-docs").permitAll()
                // swagger end
                .antMatchers("/druid/**").permitAll()

                // 文件
                .antMatchers(Constants.RESOURCE_PREFIX + "/**").permitAll()
                // 其他
                .antMatchers(CommonConst.WEB_REST_SERVICE_PREFICX + "auth/login/wx/**").permitAll()
                // websocket
                .antMatchers("/websocket/**").permitAll()
                // 支付宝回调
                .antMatchers("/api/aliPay/return").permitAll()
                .antMatchers("/api/aliPay/notify").permitAll()
                // 系统监控
                .antMatchers("/actuator/**").permitAll()
                // 接口限流测试
                .antMatchers("/test/**").permitAll()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                // 文章查询服务
                .antMatchers("/app/api/service/ebookarticle/queryPage").permitAll()
                .antMatchers("/app/api/service/ebookarticle/get").permitAll()
                .antMatchers("/app/api/service/prouser/getAddressBook").permitAll()
                .antMatchers("/app/api/service/prodept/getProDeptTreeByLevelCode").permitAll()
                .antMatchers("/app/api/service/prouser/get").permitAll()
                .antMatchers("/app/api/service/formleave/insert").permitAll()
                .antMatchers("/app/api/service/systemnotice/getAll").permitAll()
                .antMatchers("/app/api/service/systemnotice/get").permitAll()
                .antMatchers("/app/api/service/systemnoticefile/getAll").permitAll()
                .antMatchers("/app/api/service/formleave/getAll").permitAll()
                .antMatchers("/app/api/service/timesheetdetails/insert").permitAll()
                .antMatchers("/app/api/service/**").permitAll()
                .antMatchers("/web/api/service/proresourceworkflow/insertBatch").permitAll()
                .antMatchers("/web/api/service/wxmsg/sendWxMsgTemplate").permitAll()
//                .antMatchers("/web/api/service/prouser/get").permitAll()
                .antMatchers("/app/api/service/prouser/register").permitAll()
                .antMatchers("/app/api/service/prouser/sendCode").permitAll()
                // wx监控
                .antMatchers("/wx/**").permitAll()
                .antMatchers("/v1/3rd/**").permitAll()

                .antMatchers("/web/api/service/promenu/getAllForProMenuByUserIdNew").permitAll()//测试菜单构建放开权限

                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                // 防止iframe 造成跨域
                .and().headers().frameOptions().disable();

        //设置可以iframe访问
        httpSecurity.headers().frameOptions().sameOrigin();
        httpSecurity.logout().logoutUrl("/api/service/auth" + logout).logoutSuccessHandler(jwtLogoutSuccessHandler);

        // 添加JWT filter
        httpSecurity
                .addFilterBefore(jwtAuthorizationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        // 添加CORS filter
        httpSecurity.addFilterBefore(corsFilter, JwtAuthorizationTokenFilter.class);
        httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);

        /*httpSecurity
                //定制url访问权限，动态权限读取，参考：https://www.jianshu.com/p/0a06496e75ea
                .addFilterBefore(dynamicallyUrlInterceptor(), FilterSecurityInterceptor.class);*/
    }

}
