package com.yiboshi.science.config.security;


import com.yiboshi.science.config.annotation.Anonymous;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private AuthorizationAccessDeniedHandler customAccessDeniedHandler;

    @Autowired
    private AuthExceptionEntryPointHandler authExceptionEntryPoint;

    @Autowired
    private WebApplicationContext applicationContext;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.authenticationEntryPoint(authExceptionEntryPoint);
        resources.accessDeniedHandler(customAccessDeniedHandler);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        Set<String> anonymous = getAnonymousUrl();
        http.httpBasic()
                .and()
                .formLogin()
                //.and().rememberMe()
                //.authenticationSuccessHandler(new  ....)
                //密钥
                //.key("unique-and-secret")
                //cookie名
                //.rememberMeCookieName("remember-me-cookie-name")
                //生命周期，单位毫秒
                //.tokenValiditySeconds(24 * 60 * 60)
                /*.and()
                .logout()
                .logoutSuccessHandler(userLogoutSuccessHandler)*/
                .and()
                .authorizeRequests()
                .antMatchers(anonymous.toArray(new String[0])).permitAll()
                .antMatchers("/error").permitAll()
                .antMatchers("/upload/files/**").permitAll()
                .antMatchers("/docs.html").permitAll()
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/v2/api-docs").permitAll()
                .antMatchers("/api-docs").permitAll()
//              .antMatchers("/oauth/token").permitAll()
//              .antMatchers("/oauth/check_token").permitAll()
                .anyRequest()
                //.permitAll()
                .authenticated()
                .and().csrf().disable().cors()
                .and().exceptionHandling()
                .authenticationEntryPoint(authExceptionEntryPoint)
                .accessDeniedHandler(customAccessDeniedHandler);
        //.and().sessionManagement().maximumSessions(1);
    }

    public Set<String> getAnonymousUrl() {
        RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
        // 获取url与类和方法的对应信息
        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
        Set<String> set = new HashSet<>();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : map.entrySet()) {
            Map<String, String> map1 = new HashMap<String, String>();
            RequestMappingInfo info = m.getKey();
            HandlerMethod method = m.getValue();
            Anonymous anonymous = method.getMethodAnnotation(Anonymous.class);
            if (null != anonymous) {
                PatternsRequestCondition p = info.getPatternsCondition();
                for (String url : p.getPatterns()) {
                    set.add(url);
                }
            }
        }
        return set;
    }
}
