package ink.wgink.login.base.security;

import ink.wgink.common.handler.AccessDenyHandler;
import ink.wgink.interfaces.expand.login.ILoginHandlerService;
import ink.wgink.interfaces.user.mongo.IMongoLoginUserService;
import ink.wgink.login.base.handler.LoginFailureHandler;
import ink.wgink.login.base.handler.LogoutHandler;
import ink.wgink.login.base.security.user.UserSecurityConfig;
import ink.wgink.login.base.service.user.UserDetailServiceImpl;
import ink.wgink.login.base.service.user.UserLoginService;
import ink.wgink.properties.BaseProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.servlet.http.HttpSession;

/**
 * @ClassName: WebSecurityConfig
 * @Description: security配置
 * @Author: WangGeng
 * @Date: 2019/2/15 10:05 AM
 * @Version: 1.0
 **/
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private BaseProperties baseProperties;
    @Autowired
    private UserDetailServiceImpl userDetailService;
    @Autowired
    private UserLoginService userLoginService;
    @Autowired(required = false)
    private ILoginHandlerService loginHandler;
    @Autowired
    private HttpSession httpSession;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired(required = false)
    private IMongoLoginUserService mongoLoginUserService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * 默认放行配置
         */
        String[] defaultAntMatchers = {
                baseProperties.getLoginUrl(),
                baseProperties.getLoginProcess(),
                baseProperties.getLoginFailure(),
                "/oauth/**",
                "/oauth2_client/**",
        };
        LoginFailureHandler loginFailureHandler = new LoginFailureHandler(baseProperties.getLoginFailure());
        http
                .formLogin()
                .loginPage(baseProperties.getLoginUrl())
                .loginProcessingUrl(baseProperties.getLoginProcess())
                .failureForwardUrl(baseProperties.getLoginUrl())
                .failureHandler(loginFailureHandler)
                .and()
                .logout()
                .addLogoutHandler(new LogoutHandler())
                .and()
                .headers()
                .frameOptions()
                .disable()
                .and()
                .authorizeRequests()
                .antMatchers(defaultAntMatchers)
                .permitAll()
                .anyRequest().access("@accessWhiteList.hasPermission(request, authentication)")
                .and()
                .exceptionHandling().accessDeniedHandler(new AccessDenyHandler())
                .and()
                .cors()
                .and()
                .csrf()
                .disable();
        addUserAuthenticationFilter(http, loginFailureHandler);
    }

    /**
     * 创建用户认证过滤器链，替换原有UsernamePasswordAuthenticationFilter
     *
     * @param http
     * @param loginFailureHandler
     */
    private void addUserAuthenticationFilter(HttpSecurity http, LoginFailureHandler loginFailureHandler) throws Exception {
        UserSecurityConfig userSecurityConfig = new UserSecurityConfig();
        userSecurityConfig.setUserDetailService(userDetailService);
        userSecurityConfig.setPasswordEncoder(passwordEncoder);
        userSecurityConfig.setLoginProcessUrl(baseProperties.getLoginProcess());
        userSecurityConfig.setLoginFailureHandler(loginFailureHandler);
        userSecurityConfig.setUserLoginService(userLoginService);
        userSecurityConfig.setLoginHandler(loginHandler);
        userSecurityConfig.setHttpSession(httpSession);
        userSecurityConfig.setMongoLoginUserService(mongoLoginUserService);
        http.apply(userSecurityConfig);
    }

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

}
