employee-service调用department-service,如果要按OAUTH2.0流程,只需要提供client-id和client-secrect即可。在KEYCLOAK中引入service-account,即配置该employee-service时,取消standard-flow,同时激活service-account。 
employee-service的application.yaml文件,其中的public-key要从KEYCLOAK中取  
server:  
   port: 8090  
# Can be set to false to disable security during local development  
rest:  
   security:  
      enabled: true  
      #issuer-uri: http://localhost:8080/auth/realms/dev  
      api-matcher: /api/**  
      cors:  
         allowed-origins: '*'  
         allowed-headers: '*'  
         allowed-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS  
         max-age: 3600  
  
security:  
   oauth2:  
      resource:  
         filter-order: 3  
         id: test-employee-service  
         token-info-uri: ${rest.security.issuer-uri}/protocol/openid-connect/token/introspect  
         user-info-uri: ${rest.security.issuer-uri}/protocol/openid-connect/userinfo  
         jwt:  
            key-value: |   
               -----BEGIN PUBLIC KEY-----  
               MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB  
               -----END PUBLIC KEY-----  
  
# To access another secured micro-service  
      client:  
         client-id: test-employee-service  
         #client-secret: 25c33006-e1b9-4fc2-a6b9-c43dbc41ecd0  
         user-authorization-uri: ${rest.security.issuer-uri}/protocol/openid-connect/auth  
         access-token-uri: ${rest.security.issuer-uri}/protocol/openid-connect/token  
         scope: openid  
         grant-type: client_credentials  
         is-client-only: true  
  
#Logging Configuration  
logging:  
   level:  
      org.springframework.boot.autoconfigure.logging: INFO  
      org.springframework.security: DEBUG  
      org.arun: DEBUG  
      root: INFO
 application-dev.yaml  
rest:  
   security:  
      issuer-uri: http://10.80.27.69:8180/auth/realms/quickstart  
  
department-service:  
   url: http://10.80.27.69:8095/api/departments/1  
  
security:  
   oauth2:  
      client:  
         client-secret: db25cdbd-605b-429d-bd92-96705bdf1474
 department-service的application.yaml  
server:  
   port: 8095  
# Can be set to false to disable security during local development  
rest:  
   security:  
      enabled: true  
      #issuer-uri: http://localhost:8080/auth/realms/dev  
      api-matcher: /api/**  
      cors:  
         allowed-origins: '*'  
         allowed-headers: '*'  
         allowed-methods: GET,POST,PUT,PATCH,DELETE,OPTIONS  
         max-age: 3600  
  
security:  
   oauth2:  
      resource:  
         filter-order: 3  
         id: test-department-service  
         token-info-uri: ${rest.security.issuer-uri}/protocol/openid-connect/token/introspect  
         user-info-uri: ${rest.security.issuer-uri}/protocol/openid-connect/userinfo  
         jwt:  
            key-value: |   
               -----BEGIN PUBLIC KEY-----  
               MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB  
               -----END PUBLIC KEY-----  
  
#Logging Configuration  
logging:  
   level:  
      org.springframework.boot.autoconfigure.logging: INFO  
      org.springframework.security: DEBUG  
      org.arun: DEBUG  
      root: INFO
 application-dev.yaml  
rest:  
   security:  
      issuer-uri: http://10.80.27.69:8180/auth/realms/quickstart
 employee-service的pom.xml  
<?xml version="1.0" encoding="UTF-8"?>  
<project xmlns="http://maven.apache.org/POM/4.0.0"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
    <modelVersion>4.0.0</modelVersion>  
    <parent>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-parent</artifactId>  
        <version>2.1.18.RELEASE</version>  
        <relativePath /> <!-- lookup parent from repository -->  
    </parent>  
    <groupId>org.arun.springoauth</groupId>  
    <artifactId>spring-oauth2-employee-service</artifactId>  
    <version>1.0.0</version>  
    <name>spring-oauth2-employee-service</name>  
    <description>Employee Service</description>  
  
    <properties>  
        <java.version>1.8</java.version>  
        <spring-boot.version>2.1.18.RELEASE</spring-boot.version>  
    </properties>  
  
    <dependencies>  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-security</artifactId>  
        </dependency>  
  
        <dependency>  
            <groupId>org.springframework.security.oauth.boot</groupId>  
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>  
            <!-- <version>2.1.18.RELEASE</version> -->  
            <version>${spring-boot.version}</version>  
        </dependency>  
  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-web</artifactId>  
        </dependency>  
  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-devtools</artifactId>  
            <scope>runtime</scope>  
        </dependency>  
  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-configuration-processor</artifactId>  
            <optional>true</optional>  
        </dependency>  
  
        <dependency>  
            <groupId>org.projectlombok</groupId>  
            <artifactId>lombok</artifactId>  
            <optional>true</optional>  
        </dependency>  
  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-test</artifactId>  
            <scope>test</scope>  
        </dependency>  
  
        <dependency>  
            <groupId>org.springframework.security</groupId>  
            <artifactId>spring-security-test</artifactId>  
            <scope>test</scope>  
        </dependency>  
    </dependencies>  
  
    <build>  
        <plugins>  
            <plugin>  
                <groupId>org.springframework.boot</groupId>  
                <artifactId>spring-boot-maven-plugin</artifactId>  
                <configuration>  
                    <layout>ZIP</layout>  
                    <excludes>  
                        <exclude>  
                            <groupId>*</groupId>  
                            <artifactId>*</artifactId>  
                        </exclude>  
                    </excludes>  
                    <includes>  
                        <include>  
                            <groupId>com.paul</groupId>  
                        </include>  
                    </includes>  
                </configuration>  
            </plugin>  
        </plugins>  
    </build>  
  
</project>
 将jwt格式的access_token转成Authentication的类JwtAccessTokenCustomizer  
package org.arun.springoauth.employee.config;  
  
import com.fasterxml.jackson.databind.JsonNode;  
import com.fasterxml.jackson.databind.ObjectMapper;  
import java.util.HashSet;  
import java.util.List;  
import java.util.Map;  
import java.util.Set;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.boot.autoconfigure.security.oauth2.resource.JwtAccessTokenConverterConfigurer;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;  
import org.springframework.security.core.Authentication;  
import org.springframework.security.core.GrantedAuthority;  
import org.springframework.security.core.authority.AuthorityUtils;  
import org.springframework.security.oauth2.provider.OAuth2Authentication;  
import org.springframework.security.oauth2.provider.OAuth2Request;  
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;  
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;  
  
@Configuration  
public class JwtAccessTokenCustomizer extends DefaultAccessTokenConverter implements JwtAccessTokenConverterConfigurer {  
  
    private static final Logger LOG = LoggerFactory.getLogger(JwtAccessTokenCustomizer.class);  
  
    private static final String CLIENT_NAME_ELEMENT_IN_JWT = "resource_access";  
  
    private static final String ROLE_ELEMENT_IN_JWT = "roles";  
  
    private ObjectMapper mapper;  
  
    @Autowired  
    public JwtAccessTokenCustomizer(ObjectMapper mapper) {  
        this.mapper = mapper;  
        LOG.info("Initialized {}", JwtAccessTokenCustomizer.class.getSimpleName());  
    }  
  
    @Override  
    public void configure(JwtAccessTokenConverter converter) {  
        converter.setAccessTokenConverter(this);  
        LOG.info("Configured {}", JwtAccessTokenConverter.class.getSimpleName());  
    }  
  
    /**  
     * Spring oauth2 expects roles under authorities element in tokenMap, but  
     * keycloak provides it under resource_access. Hence extractAuthentication  
     * method is overriden to extract roles from resource_access.  
     *  
     * @return OAuth2Authentication with authorities for given application  
     */  
    @Override  
    public OAuth2Authentication extractAuthentication(Map<String, ?> tokenMap) {  
        LOG.debug("Begin extractAuthentication: tokenMap = {}", tokenMap);  
        JsonNode token = mapper.convertValue(tokenMap, JsonNode.class);  
        Set<String> audienceList = extractClients(token); // extracting client names  
        List<GrantedAuthority> authorities = extractRoles(token); // extracting client roles  
  
        OAuth2Authentication authentication = super.extractAuthentication(tokenMap);  
        OAuth2Request oAuth2Request = authentication.getOAuth2Request();  
  
        OAuth2Request request = new OAuth2Request(oAuth2Request.getRequestParameters(), oAuth2Request.getClientId(),  
                authorities, true, oAuth2Request.getScope(), audienceList, null, null, null);  
  
        Authentication usernamePasswordAuthentication = new UsernamePasswordAuthenticationToken(  
                authentication.getPrincipal(), "N/A", authorities);  
        LOG.debug("End extractAuthentication");  
        return new OAuth2Authentication(request, usernamePasswordAuthentication);  
    }  
  
    private List<GrantedAuthority> extractRoles(JsonNode jwt) {  
        LOG.debug("Begin extractRoles: jwt = {}", jwt);  
        Set<String> rolesWithPrefix = new HashSet<>();  
  
        jwt.path(CLIENT_NAME_ELEMENT_IN_JWT).elements().forEachRemaining(e -> e.path(ROLE_ELEMENT_IN_JWT).elements()  
                .forEachRemaining(r -> rolesWithPrefix.add("ROLE_" + r.asText())));  
  
        final List<GrantedAuthority> authorityList = AuthorityUtils  
                .createAuthorityList(rolesWithPrefix.toArray(new String[0]));  
        LOG.debug("End extractRoles: roles = {}", authorityList);  
        return authorityList;  
    }  
  
    private Set<String> extractClients(JsonNode jwt) {  
        LOG.debug("Begin extractClients: jwt = {}", jwt);  
        if (jwt.has(CLIENT_NAME_ELEMENT_IN_JWT)) {  
            JsonNode resourceAccessJsonNode = jwt.path(CLIENT_NAME_ELEMENT_IN_JWT);  
            final Set<String> clientNames = new HashSet<>();  
            resourceAccessJsonNode.fieldNames().forEachRemaining(clientNames::add);  
  
            LOG.debug("End extractClients: clients = {}", clientNames);  
            return clientNames;  
  
        } else {  
            throw new IllegalArgumentException(  
                    "Expected element " + CLIENT_NAME_ELEMENT_IN_JWT + " not found in token");  
        }  
  
    }  
  
}
   Reference  
https://medium.com/@bcarunmail/securing-rest-api-using-keycloak-and-spring-oauth2-6ddf3a1efcc2