Skip to content

Commit e307474

Browse files
committed
update oauth security
1 parent 8141d46 commit e307474

File tree

10 files changed

+431
-7
lines changed

10 files changed

+431
-7
lines changed

auth-service/src/main/java/cn/zhangxd/auth/config/OAuthConfiguration.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package cn.zhangxd.auth.config;
22

3-
import javax.sql.DataSource;
4-
53
import org.springframework.beans.factory.annotation.Autowired;
64
import org.springframework.context.annotation.Bean;
75
import org.springframework.context.annotation.Configuration;
@@ -20,6 +18,8 @@
2018
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
2119
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
2220

21+
import javax.sql.DataSource;
22+
2323
@Configuration
2424
@EnableAuthorizationServer
2525
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {
@@ -63,13 +63,22 @@ public void configure(ClientDetailsServiceConfigurer clients)
6363
clients.jdbc(dataSource)
6464
.passwordEncoder(passwordEncoder)
6565
.withClient("client")
66-
.authorizedGrantTypes("authorization_code", "client_credentials",
67-
"refresh_token", "password", "implicit")
66+
.authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token", "password", "implicit")
6867
.authorities("ROLE_CLIENT")
69-
.resourceIds("apis")
7068
.scopes("read")
7169
.secret("secret")
72-
.accessTokenValiditySeconds(300);
70+
.accessTokenValiditySeconds(300)
71+
.and()
72+
.withClient("svca-service")
73+
.secret("password")
74+
.authorizedGrantTypes("client_credentials", "refresh_token")
75+
.scopes("server")
76+
.and()
77+
.withClient("svcb-service")
78+
.secret("password")
79+
.authorizedGrantTypes("client_credentials", "refresh_token")
80+
.scopes("server")
81+
;
7382

7483
}
7584

svca-service/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
<name>${project.artifactId}</name>
1717

1818
<dependencies>
19+
<dependency>
20+
<groupId>org.springframework.cloud</groupId>
21+
<artifactId>spring-cloud-starter-oauth2</artifactId>
22+
</dependency>
23+
1924
<dependency>
2025
<groupId>org.springframework.cloud</groupId>
2126
<artifactId>spring-cloud-starter-eureka</artifactId>

svca-service/src/main/java/cn/zhangxd/svca/ServiceAApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
66
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
77
import org.springframework.cloud.netflix.feign.EnableFeignClients;
8+
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
89

910

1011
@EnableDiscoveryClient
1112
@EnableFeignClients
1213
@SpringBootApplication
1314
@EnableCircuitBreaker
15+
@EnableOAuth2Client
1416
public class ServiceAApplication {
1517

1618
public static void main(String[] args) {
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package cn.zhangxd.svca.config;
2+
3+
import org.apache.commons.logging.Log;
4+
import org.apache.commons.logging.LogFactory;
5+
import org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor;
6+
import org.springframework.boot.autoconfigure.security.oauth2.resource.FixedAuthoritiesExtractor;
7+
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
8+
import org.springframework.security.core.AuthenticationException;
9+
import org.springframework.security.core.GrantedAuthority;
10+
import org.springframework.security.oauth2.client.OAuth2RestOperations;
11+
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
12+
import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails;
13+
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
14+
import org.springframework.security.oauth2.common.OAuth2AccessToken;
15+
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
16+
import org.springframework.security.oauth2.provider.OAuth2Authentication;
17+
import org.springframework.security.oauth2.provider.OAuth2Request;
18+
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
19+
20+
import java.util.*;
21+
22+
/**
23+
* Extended implementation of {@link org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices}
24+
*
25+
* By default, it designed to return only user details. This class provides {@link #getRequest(Map)} method, which
26+
* returns clientId and scope of calling service. This information used in controller's security checks.
27+
*/
28+
29+
public class CustomUserInfoTokenServices implements ResourceServerTokenServices {
30+
31+
protected final Log logger = LogFactory.getLog(getClass());
32+
33+
private static final String[] PRINCIPAL_KEYS = new String[] { "user", "username",
34+
"userid", "user_id", "login", "id", "name" };
35+
36+
private final String userInfoEndpointUrl;
37+
38+
private final String clientId;
39+
40+
private OAuth2RestOperations restTemplate;
41+
42+
private String tokenType = DefaultOAuth2AccessToken.BEARER_TYPE;
43+
44+
private AuthoritiesExtractor authoritiesExtractor = new FixedAuthoritiesExtractor();
45+
46+
public CustomUserInfoTokenServices(String userInfoEndpointUrl, String clientId) {
47+
this.userInfoEndpointUrl = userInfoEndpointUrl;
48+
this.clientId = clientId;
49+
}
50+
51+
public void setTokenType(String tokenType) {
52+
this.tokenType = tokenType;
53+
}
54+
55+
public void setRestTemplate(OAuth2RestOperations restTemplate) {
56+
this.restTemplate = restTemplate;
57+
}
58+
59+
public void setAuthoritiesExtractor(AuthoritiesExtractor authoritiesExtractor) {
60+
this.authoritiesExtractor = authoritiesExtractor;
61+
}
62+
63+
@Override
64+
public OAuth2Authentication loadAuthentication(String accessToken)
65+
throws AuthenticationException, InvalidTokenException {
66+
Map<String, Object> map = getMap(this.userInfoEndpointUrl, accessToken);
67+
if (map.containsKey("error")) {
68+
this.logger.debug("userinfo returned error: " + map.get("error"));
69+
throw new InvalidTokenException(accessToken);
70+
}
71+
return extractAuthentication(map);
72+
}
73+
74+
private OAuth2Authentication extractAuthentication(Map<String, Object> map) {
75+
Object principal = getPrincipal(map);
76+
OAuth2Request request = getRequest(map);
77+
List<GrantedAuthority> authorities = this.authoritiesExtractor
78+
.extractAuthorities(map);
79+
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
80+
principal, "N/A", authorities);
81+
token.setDetails(map);
82+
return new OAuth2Authentication(request, token);
83+
}
84+
85+
private Object getPrincipal(Map<String, Object> map) {
86+
for (String key : PRINCIPAL_KEYS) {
87+
if (map.containsKey(key)) {
88+
return map.get(key);
89+
}
90+
}
91+
return "unknown";
92+
}
93+
94+
@SuppressWarnings({ "unchecked" })
95+
private OAuth2Request getRequest(Map<String, Object> map) {
96+
Map<String, Object> request = (Map<String, Object>) map.get("oauth2Request");
97+
98+
String clientId = (String) request.get("clientId");
99+
Set<String> scope = new LinkedHashSet<>(request.containsKey("scope") ?
100+
(Collection<String>) request.get("scope") : Collections.<String>emptySet());
101+
102+
return new OAuth2Request(null, clientId, null, true, new HashSet<>(scope),
103+
null, null, null, null);
104+
}
105+
106+
@Override
107+
public OAuth2AccessToken readAccessToken(String accessToken) {
108+
throw new UnsupportedOperationException("Not supported: read access token");
109+
}
110+
111+
@SuppressWarnings({ "unchecked" })
112+
private Map<String, Object> getMap(String path, String accessToken) {
113+
this.logger.debug("Getting user info from: " + path);
114+
try {
115+
OAuth2RestOperations restTemplate = this.restTemplate;
116+
if (restTemplate == null) {
117+
BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails();
118+
resource.setClientId(this.clientId);
119+
restTemplate = new OAuth2RestTemplate(resource);
120+
}
121+
OAuth2AccessToken existingToken = restTemplate.getOAuth2ClientContext()
122+
.getAccessToken();
123+
if (existingToken == null || !accessToken.equals(existingToken.getValue())) {
124+
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(
125+
accessToken);
126+
token.setTokenType(this.tokenType);
127+
restTemplate.getOAuth2ClientContext().setAccessToken(token);
128+
}
129+
return restTemplate.getForEntity(path, Map.class).getBody();
130+
}
131+
catch (Exception ex) {
132+
this.logger.info("Could not fetch user details: " + ex.getClass() + ", "
133+
+ ex.getMessage());
134+
return Collections.<String, Object>singletonMap("error",
135+
"Could not fetch user details");
136+
}
137+
}
138+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package cn.zhangxd.svca.config;
2+
3+
import feign.RequestInterceptor;
4+
import org.springframework.beans.factory.annotation.Autowired;
5+
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
6+
import org.springframework.boot.context.properties.ConfigurationProperties;
7+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
8+
import org.springframework.cloud.security.oauth2.client.feign.OAuth2FeignRequestInterceptor;
9+
import org.springframework.context.annotation.Bean;
10+
import org.springframework.context.annotation.Configuration;
11+
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
12+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
13+
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
14+
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
15+
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
16+
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
17+
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
18+
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
19+
20+
@Configuration
21+
@EnableResourceServer
22+
@EnableGlobalMethodSecurity(prePostEnabled = true)
23+
@EnableConfigurationProperties
24+
public class ServiceAConfiguration extends ResourceServerConfigurerAdapter {
25+
26+
@Autowired
27+
private ResourceServerProperties sso;
28+
29+
@Bean
30+
@ConfigurationProperties(prefix = "security.oauth2.client")
31+
public ClientCredentialsResourceDetails clientCredentialsResourceDetails() {
32+
return new ClientCredentialsResourceDetails();
33+
}
34+
35+
@Bean
36+
public RequestInterceptor oauth2FeignRequestInterceptor() {
37+
return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), clientCredentialsResourceDetails());
38+
}
39+
40+
@Bean
41+
public OAuth2RestTemplate clientCredentialsRestTemplate() {
42+
return new OAuth2RestTemplate(clientCredentialsResourceDetails());
43+
}
44+
45+
@Bean
46+
public ResourceServerTokenServices tokenServices() {
47+
return new CustomUserInfoTokenServices(sso.getUserInfoUri(), sso.getClientId());
48+
}
49+
50+
@Override
51+
public void configure(HttpSecurity http) throws Exception {
52+
http.authorizeRequests()
53+
.antMatchers("/").permitAll()
54+
.anyRequest().authenticated();
55+
}
56+
}

svca-service/src/main/java/cn/zhangxd/svca/controller/ServiceAController.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import org.springframework.web.bind.annotation.GetMapping;
1010
import org.springframework.web.bind.annotation.RestController;
1111

12+
import java.security.Principal;
13+
1214
@RefreshScope
1315
@RestController
1416
public class ServiceAController {
@@ -26,4 +28,9 @@ public String printServiceA() {
2628
ServiceInstance serviceInstance = discoveryClient.getLocalServiceInstance();
2729
return serviceInstance.getServiceId() + " (" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + ")" + "===>name:" + name + "<br/>" + serviceBClient.printServiceB();
2830
}
31+
32+
@GetMapping(path = "/current")
33+
public Principal getCurrentAccount(Principal principal) {
34+
return principal;
35+
}
2936
}

svcb-service/pom.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
<name>${project.artifactId}</name>
1717

1818
<dependencies>
19+
<dependency>
20+
<groupId>org.springframework.cloud</groupId>
21+
<artifactId>spring-cloud-starter-oauth2</artifactId>
22+
</dependency>
23+
1924
<dependency>
2025
<groupId>org.springframework.cloud</groupId>
2126
<artifactId>spring-cloud-starter-eureka</artifactId>
@@ -42,6 +47,10 @@
4247
<groupId>org.springframework.cloud</groupId>
4348
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
4449
</dependency>
50+
<dependency>
51+
<groupId>org.springframework.cloud</groupId>
52+
<artifactId>spring-cloud-starter-feign</artifactId>
53+
</dependency>
4554
<dependency>
4655
<groupId>org.springframework.cloud</groupId>
4756
<artifactId>spring-cloud-starter-hystrix</artifactId>

svcb-service/src/main/java/cn/zhangxd/svcb/ServiceBApplication.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
55
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
66
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
7+
import org.springframework.cloud.netflix.feign.EnableFeignClients;
8+
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
79

8-
@SpringBootApplication
910
@EnableDiscoveryClient
11+
@EnableFeignClients
12+
@SpringBootApplication
1013
@EnableCircuitBreaker
14+
@EnableOAuth2Client
1115
public class ServiceBApplication {
1216

1317
public static void main(String[] args) {

0 commit comments

Comments
 (0)