package com.css.simulation.oauth.server.cofiguration.oauth;


import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;

import javax.annotation.Resource;


/**
 *
 */
@Configuration
@Slf4j
public class OauthAuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {


    @Resource
    private AuthenticationManager authenticationManager;        // 认证管理器，来自 Spring Security
    @Resource
    private UserDetailsService userDetailsService;        // 用户信息验证服务，来自 Spring Security
    @Resource
    private AccessTokenConverter accessTokenConverter;
    @Resource
    private TokenStore tokenStore;  // 令牌管理服务
    @Resource
    private AuthorizationServerTokenServices authorizationServerTokenServices;  // 令牌管理服务

    /**
     * 配置 ClientDetailsService，客户端详情信息在这里进行初始化。
     * 可以把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息。
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 通过内存方式配置客户端
        clients.inMemory()  // 内存方式
                .withClient("simulation-oauth-client")       // 客户端 id
                .secret("hPT7zVteEXvRzS41NhJXoQYqtGmai3W0")   // 客户端密钥
                .resourceIds(
                        "simulation-resource-common",
                        "simulation-resource-scheduler",
                        "simulation-resource-sever"
                )  // 客户端拥有的资源列表
                .authorizedGrantTypes("client_credentials", "password", "refresh_token") // 允许的授权方式
                .scopes("all")    // 授权范围划分
                .autoApprove(true)
                .and()
                .withClient("algorithm-client")       // 客户端 id
                .secret("hPT7zVteEXvRzS41NhJXoQYqtGmai3W0")   // 客户端密钥
                .resourceIds(
                        "simulation-resource-common",
                        "simulation-resource-scheduler",
                        "simulation-resource-sever"
                )  // 客户端拥有的资源列表
                .authorizedGrantTypes("client_credentials", "refresh_token") // 允许的授权方式
                .scopes("all")    // 授权范围划分
                .autoApprove(true)
        ; // 是否自动通过，即是否跳过 scope 选择界面，跳过的话代表将所有 scope 授权范围赋予该 client
    }

    /**
     * 配置授权类型
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        DefaultWebResponseExceptionTranslator defaultWebResponseExceptionTranslator = new DefaultWebResponseExceptionTranslator() {
            @Override
            public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
                log.error("生成token异常", e);
                ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
                HttpHeaders headers = new HttpHeaders();
                headers.setAll(responseEntity.getHeaders().toSingleValueMap());
                OAuth2Exception excBody = responseEntity.getBody();
                return new ResponseEntity<>(excBody, headers, responseEntity.getStatusCode());
            }
        };

        endpoints.authenticationManager(authenticationManager)      // 认证管理器（密码模式）
                .userDetailsService(userDetailsService)           // 用户信息管理（密码模式）
                .accessTokenConverter(accessTokenConverter)         // token 信息管理
                .tokenStore(tokenStore)   // 令牌存储
                .tokenServices(authorizationServerTokenServices)    // 令牌管理服务
                .exceptionTranslator(defaultWebResponseExceptionTranslator)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
                .pathMapping("/oauth/authorize", "/authorize")   // 自定义端点路径
                .pathMapping("/oauth/token", "/token")
                .pathMapping("/oauth/confirm_access", "/confirm_access")
                .pathMapping("/oauth/error", "/error")
                .pathMapping("/oauth/check_token", "/check_token")
                .pathMapping("/oauth/token_key", "/token_key");
    }

    /**
     * 用来配置令牌端点的安全约束
     * 公开 /oauth/check_token
     * 公开 /oauth/token_key
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security.tokenKeyAccess("permitAll()")      // oauth/token_key 公开
                .checkTokenAccess("permitAll()")    // oauth/check_token 公开
                .allowFormAuthenticationForClients();   // 表单认证，申请令牌
    }


}
