Spring 使用 Oauth2的第三方對接和token

大大的吃貨發表於2017-11-07

本文章不對token的驗證操作,只是第三方的模組對Oauth2的使用,使用場景,對一整套系統進行模組化開發,子模組的api採用主枝模組的Oauth2進行安全性驗證

在pom.xml中新增依賴

<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
</dependency>

在dev.yml檔案中新增

security:

  oauth2:
    client:
      access-token-uri: http://localhost:8080/oauth/token
      client-id: locaca-66
      client-secret: dsmfksdmfs
      client-authentication-scheme: form
      grant-type: client_credentials
    resource:

      user-info-uri: http://localhost:8080/api/check_token

token的驗證地址為 http://localhost:8080/api/check_token 

新增類

@RestController
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * CORS過濾器,填加CORS頭
     * @return CORS過濾器,供Spring使用。
     */
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        source.registerCorsConfiguration("/**/pppp/**", config);
        return new CorsFilter(source);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers("/**/index/**").permitAll()
                .antMatchers("/**/api/**").authenticated()
                .antMatchers("/**/suite/**").permitAll()
                .antMatchers("/**/userInfo/**").permitAll();
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer config) {
        config.resourceId("default")
                .expressionHandler(oauthWebSecurityExpressionHandler(applicationContext));
    }

    /**
     * 為 OAuth2WebSecurityExpressionHandler 新增 applicationContext
     * @param applicationContext Spring ApplicationContext
     * @return 新增後的 OAuth2WebSecurityExpressionHandler
     */
    @Bean
    public OAuth2WebSecurityExpressionHandler oauthWebSecurityExpressionHandler(
            ApplicationContext applicationContext) {
        OAuth2WebSecurityExpressionHandler expressionHandler =
                new OAuth2WebSecurityExpressionHandler();
        expressionHandler.setApplicationContext(applicationContext);
        return expressionHandler;
    }

}

做api的攔截操作


配置到此處,每次訪問此模組的api都會進行Oauth2的安全性驗證。會攔截所有/api開頭的api



當我想要和主模組進行資料互動時,那麼主模組的api的Oauth2我如何通過呢,我採用第三方客戶端驗證的方式去對接互動資料

新建一個類,做客戶端資訊的注入操作

@Configuration
public class OauthConfiguration {

    @Value("${security.oauth2.client.access-token-uri:}")
    String accessTokenURI;
    @Value("${security.oauth2.client.client-id:}")
    String clientID;
    @Value("${security.oauth2.client.client-secret:}")
    String clientSecret;
    @Value("${security.oauth2.client.client-authentication-scheme:}")
    String clientAuthenticationScheme;
    @Value("${security.oauth2.client.grant-type:}")
    String grantType;

    @Bean
    ClientCredentialsResourceDetails resourceDetails() {
        ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
        details.setAccessTokenUri(accessTokenURI);
        details.setClientId(clientID);
        details.setClientSecret(clientSecret);
        details.setGrantType(grantType);
        details.setAuthenticationScheme(AuthenticationScheme.valueOf(clientAuthenticationScheme));
        return details;
    }

    @Bean
    public OAuth2RestTemplate oAuth2RestTemplate() {
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails(), new DefaultOAuth2ClientContext());
        return restTemplate;
    }

}

使用方式如下

@Service
public class RestService {

    private static final Logger logger = LoggerFactory.getLogger(RestService.class);
    private OauthConfiguration oauthConfiguration;
    public RestService() {
        this.oauthConfiguration= ApplicationContextUtils.getApplicationContext().getBean(OauthConfiguration.class);
    }


    /**
     * 通用rest呼叫方法
     *
     * @param url
     * @param bean
     * @param requestBody
     * @param method
     * @param flag
     * @param <T>
     * @return
     */
    public <T> T doRest(String url, Class<T> bean, Object requestBody, HttpMethod method, Object urlVariable, boolean flag) {
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity httpEntity = new HttpEntity(requestBody, requestHeaders);
        T result = null;
        ResponseEntity<T> exchange;
        OAuth2RestTemplate oAuth2RestTemplate= oauthConfiguration.oAuth2RestTemplate();
        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
        interceptors.add(new LoggingRequestInterceptor());
        oAuth2RestTemplate.setInterceptors(interceptors);
        try {
            if (urlVariable == null) {
                exchange = oAuth2RestTemplate.exchange(url, method, httpEntity, bean);
            } else {
                if (urlVariable instanceof Map) {
                    Map<String, Object> urlVariable1 = (HashMap<String, Object>) urlVariable;
                    exchange = oAuth2RestTemplate.exchange(url, method, httpEntity, bean, urlVariable1);
                } else {
                    exchange =oAuth2RestTemplate.exchange(url, method, httpEntity, bean, urlVariable);
                }
            }
            if(exchange.getBody() == null){
                logger.debug("Response body: {}","介面返回資訊為空!");
                return null;
            }
            logger.debug("Response body: {}",exchange.getBody().toString());
            result = exchange.getBody();
        } catch (Exception e) {
            throw new ServiceUnavailableException("do rest error:" + e.getMessage());
        }
        return result;
    }
}

測試方法
public static List<Object> test(){
    String GET_DEPARTMENT_BY_USER_OID="/api/implement/selectDepartmntByEmpOid/{empOid}";
    List<Map<String, Object>> maps = (List<Map<String, Object>>) artemisRestService.doRest(GET_DEPARTMENT_BY_USER_OID, Object.class, null, HttpMethod.GET, null, false);
    return null;
}

相關文章