davidfantasy / spring-cloud-demo Goto Github PK
View Code? Open in Web Editor NEWspring cloud技术体系的实例代码
spring cloud技术体系的实例代码
How to focus on protecting a Spring Gateway or Spring Rest API (client before gateway) using single sign-on with IBM Security Verify as the identity provider (free trial).
For this example, use a gateway called order. The application allows a user to log in and manage (detail, modify) their order. Since a users order is highly private data, only the authenticated and authorized user should be able to see their order and nobody else’s.
Note, I found it very interesting **shrio-with-jwt-spring-boot-starter**
specifying JWT as the format tells IBM Security Verify to return a JWT token when requesting an access token. Otherwise it will return an Opaque token. A JWT token is required in order to protect the resource servers. The resource servers use the JWT token and validate it.
We include the standard spring-boot-starter-web
and spring-boot-starter-thymeleaf
dependencies for your basic web app to support the UI and REST functionality within the application. Since we are using the new WebClient api (instead of traditional RestTemplate) we included the spring-webflux
dependency.
We add the spring-boot-starter-oauth2-client
dependency to provide the Spring magic that will integrate with IBM Security Verify (Oauth2 and OIDC Identity provider) in order to perform the authentication and mint the access tokens.
Once you add the spring-boot-starter-oauth2-client
dependencies you will need to configure a few things. We create a class called UISecurityConfig
and override the configure(HttpSecurity http)
method to configure the filter chain. Here we configure the “/” and “/login” endpoints of the web client app to be open and permitted to all users. This is so all users can get to the main page and the login page of the application without authenticating. The oauth2Login() statement specifies that we want to login using an Oauth2 identity provider, in our case IBM Security Verify (ISV)(we will see shortly how we configure that). Note, that for ISV, we had to specify the tokenEndpoint().accessTokenResponseClient(…)
. If you drill down futher into this code, you will see that we had to create a CustomAccessTokenResponseConverter class
to convert the token response from ISV as the Spring Security default implementation did not work with ISV.
@EnableWebSecurity
public class UiSecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger LOG = LoggerFactory.getLogger(UiSecurityConfig.class);
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/", "/login**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.tokenEndpoint().accessTokenResponseClient(authorizationCodeTokenResponseClient());
}
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeTokenResponseClient() {
OAuth2AccessTokenResponseHttpMessageConverter tokenResponseHttpMessageConverter =
new OAuth2AccessTokenResponseHttpMessageConverter();
tokenResponseHttpMessageConverter.setTokenResponseConverter(new CustomAccessTokenResponseConverter());
RestTemplate restTemplate = new RestTemplate(Arrays.asList(
new FormHttpMessageConverter(), tokenResponseHttpMessageConverter));
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
DefaultAuthorizationCodeTokenResponseClient tokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient();
tokenResponseClient.setRestOperations(restTemplate);
return tokenResponseClient;
}
// This method returns filter function which will log request data
private static ExchangeFilterFunction logRequest() {
return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
LOG.info("####### GK WebClient REQUEST: ####### {} {}", clientRequest.method(), clientRequest.url());
clientRequest.headers().forEach((name, values) -> values.forEach(value -> LOG.info("### GK WebClient HEADER ### {}={}", name, value)));
return Mono.just(clientRequest);
});
}
}
In order to integrate with IBM Security Verify (ISV), we had to specify tokenEndpoint().accessTokenResponseClient(…)
. If you drill down futher into this code, you will see that we had to create and use a new class CustomAccessTokenResponseConverter
to convert the token response as the Spring Security default implementation did not work with ISV. The method authorizationCodeTokenResponseClient on line 17 is responsible for calling the token endpoint on the Authorization Server (IBM Security Verify) and returning the token response which contains the JWT access token among other things.
Here is an example of a token response from IBM Security Verify. The access_token is a JWT token which contains the claims of the logged in user.
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InNlcnZlciJ9.eyJ1bmlxdWVTZWN1cml0eU5hbWUiOiI2NTIwMDE4SFFUIiwiY2xpZW50X2lkIjoiZjNlOTg4OTktNzU4NC00YTM0LWE4NTUtOTEyNjRiOGRlOTdhIiwicmVhbG1OYW1lIjoiY2xvdWRJZGVudGl0eVJlYWxtIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZ2tvdmFuQGhvdG1haWwuY29tIiwiYXVkIjoiZjNlOTg4OTktNzU4NC00YTM0LWE4NTUtOTEyNjRiOGRlOTdhIiwiZ3JhbnRfdHlwZSI6ImF1dGhvcml6YXRpb25fY29kZSIsImFjciI6InVybjppYm06c2VjdXJpdHk6cG9saWN5OmlkOjEiLCJncmFudF9pZCI6ImVmMjFjNThjLWRiYzktNDgwOC1hODI0LTk2N2RkZjM1YTdhNyIsInVzZXJUeXBlIjoicmVndWxhciIsImF1dGhfdGltZSI6MTYxNjE4NjI3OCwic2NvcGUiOiJyZWFkIGdrIG9wZW5pZCB3cml0ZSIsImp0aSI6InNDQmQ2TDFZaUNlbkJodjJzOHd6NUt4N2lPWEQzVSIsImlzcyI6Imh0dHBzOi8vZ2tvdmFuLnZlcmlmeS5pYm0uY29tL29pZGMvZW5kcG9pbnQvZGVmYXVsdCIsInN1YiI6IjY1MjAwMThIUVQiLCJpYXQiOjE2MTYxODY1NTAsImV4cCI6MTYxNjE5Mzc1MH0.PWJDgTTff5lBrpt7ExOhs5emF8pG1t_3DGihG7k54D7AsxU7otv3QCHm3JlyQ8i9y81LhyurQoKkgAioYr8jK0ET8Wc8mr6k3Dhi502PVAhtLPhIGyy2yI0e_O_HzeWRaWGrdw9gAXx-Al1YX5I6cWVshgfZUCuxOP15XSdXvl28vEP8tHDps7ET4UjVAz_IrM4H6sLIudhIn0JEd3psHRrNdmcWV4Exs_Qk2MLq8T9l0AxG-WZIhuRzba-R-1wlQfLOmgtgBfagtW9124FBxoQGT-FOxBan5un4Nf1Nv1BZjOwJlMJ59owWA4_iV_y-NB_QcBmXpDVbO-Bp068xVg",
"expires_in": 7199,
"grant_id": "ef21c58c-dbc9-4808-a824-967ddf35a7a7",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InNlcnZlciJ9.eyJhY3IiOiJ1cm46aWJtOnNlY3VyaXR5OnBvbGljeTppZDoxIiwidXNlclR5cGUiOiJyZWd1bGFyIiwic19oYXNoIjoiRWs0TGNnR3dPSTE4Ql9ReGxMbGtYUSIsInVuaXF1ZVNlY3VyaXR5TmFtZSI6IjY1MjAwMThIUVQiLCJkaXNwbGF5TmFtZSI6IkdlcnJ5IEtvdmFuIiwianRpIjoiSll1Z3ZWY3NBelVZd2tGWDN4S2VKQkdTdHhxdnd3IiwicmVhbG1OYW1lIjoiY2xvdWRJZGVudGl0eVJlYWxtIiwibmFtZSI6IkdlcnJ5IEtvdmFuIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZ2tvdmFuQGhvdG1haWwuY29tIiwibm9uY2UiOiJjeGttY3A2ZmllIiwiZXh0Ijp7InRlbmFudElkIjoiZ2tvdmFuLnZlcmlmeS5pYm0uY29tIn0sImlzcyI6Imh0dHBzOi8vZ2tvdmFuLnZlcmlmeS5pYm0uY29tL29pZGMvZW5kcG9pbnQvZGVmYXVsdCIsImF1ZCI6ImYzZTk4ODk5LTc1ODQtNGEzNC1hODU1LTkxMjY0YjhkZTk3YSIsInN1YiI6IjY1MjAwMThIUVQiLCJpYXQiOjE2MTYxODY1NTAsImV4cCI6MTYxNjE5Mzc1MCwiYXRfaGFzaCI6IjZFOFlCTm9GOHF5SkNPblhpYS15RXcifQ.Ouu1Tt-U0kEzDR8asoMAUQiTqaQL_Vjtn04pICqyCM7rBB3jmOTuAsLIeDsWA7QkKisWTJr5ux4L7unCLf0cRKFuWlEbk-e_XP4QM9boojm9B-GFQue3oDSY4NXTo3dsjnL_IDUhcEWwSwpexpDgrW3wT9vIlvURnj-kqKqaAvX-y3bF89z4nRwBN0R-IzYuw3WuqFdGZLByEVpPl6WdbvXDbQcZWvqoC4tB-n5cN-RZePo2XKbwLZMlpg5fYzOnx6GHinFlrtyXBWcaV7bp5yo_2Y7_ypvnzxAb4_OTUzvLMfXMb_tICLt9dBKllbhruIJIOGz7C6FtbLF-ZlDKMQ",
"scope": "read openid write",
"token_type": "jwt"
}
Notice that the value for the token_type field is “jwt”. The default implementation in the Spring Security token response converter expects this field to have the value of “Bearer” and that is why we needed to create our custom implementation.
Below is the implementation of the CustomAccessTokenResponseConverter
.
You will notice that this code does not check/validate the value of the token_type parameter. Instead on line 14, we just hard code the token type to Bearer
set the other other fields accordingly and return the token response object.
public class CustomAccessTokenResponseConverter implements Converter<Map<String, String>, OAuth2AccessTokenResponse> {
private static final Set<String> TOKEN_RESPONSE_PARAMETER_NAMES = Stream.of(
OAuth2ParameterNames.ACCESS_TOKEN,
OAuth2ParameterNames.TOKEN_TYPE,
OAuth2ParameterNames.EXPIRES_IN,
OAuth2ParameterNames.REFRESH_TOKEN,
OAuth2ParameterNames.SCOPE).collect(Collectors.toSet());
@Override
public OAuth2AccessTokenResponse convert(Map<String, String> tokenResponseParameters) {
String accessToken = tokenResponseParameters.get(OAuth2ParameterNames.ACCESS_TOKEN);
OAuth2AccessToken.TokenType accessTokenType = OAuth2AccessToken.TokenType.BEARER;
long expiresIn = 0;
if (tokenResponseParameters.containsKey(OAuth2ParameterNames.EXPIRES_IN)) {
try {
expiresIn = Long.valueOf(tokenResponseParameters.get(OAuth2ParameterNames.EXPIRES_IN));
} catch (NumberFormatException ex) { }
}
Set<String> scopes = Collections.emptySet();
if (tokenResponseParameters.containsKey(OAuth2ParameterNames.SCOPE)) {
String scope = tokenResponseParameters.get(OAuth2ParameterNames.SCOPE);
scopes = Arrays.stream(StringUtils.delimitedListToStringArray(scope, " ")).collect(Collectors.toSet());
}
Map<String, Object> additionalParameters = new LinkedHashMap<>();
tokenResponseParameters.entrySet().stream()
.filter(e -> !TOKEN_RESPONSE_PARAMETER_NAMES.contains(e.getKey()))
.forEach(e -> additionalParameters.put(e.getKey(), e.getValue()));
return OAuth2AccessTokenResponse.withToken(accessToken)
.tokenType(accessTokenType)
.expiresIn(expiresIn)
.scopes(scopes)
.additionalParameters(additionalParameters)
.build();
}
}
Finally, we need to configure the appropriate Spring Security oauth2 parameters in the application.yml file as shown below:
spring:
security:
oauth2:
client:
registration:
custom:
client-id: ${CLIENT_ID}
client-secret: ${CLIENT_SECRET}
scope: read,write,openid
authorization-grant-type: authorization_code
redirect-uri: http://<url>:9000/login/oauth2/code/custom
provider:
custom:
authorization-uri: https://<tenantid>.verify.ibm.com/oidc/endpoint/default/authorize
token-uri: https://<tenantid>.verify.ibm.com/oidc/endpoint/default/token
user-info-uri: https://<tenantid>.verify.ibm.com/oidc/endpoint/default/userinfo
user-name-attribute: preferred_username
issuer-uri: https://<tenantid>.verify.ibm.com/oidc/endpoint/default
jwk-set-uri: https://<tenantid>.verify.ibm.com/v1.0/endpoint/default/jwks
...
resource server
To configure the resource we extend the Spring Security WebSecurityConfigurerAdapter
class as follows:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {// @formatter:off
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.cors()
.and()
.authorizeRequests()
.antMatchers("/open/api/test").permitAll()
.antMatchers(HttpMethod.GET, "/order-service/**", "/user/info")
.hasAuthority("SCOPE_read")
.antMatchers(HttpMethod.POST, "/api/foos")
.hasAuthority("SCOPE_write")
.anyRequest()
.authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
}
The application.yml for the resource server configuration is as follows:
# resource server configuration properties
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://<tenatid>.verify.ibm.com/oidc/endpoint/default
jwk-set-uri: https://<tenatid>.verify.ibm.com/v1.0/endpoint/default/jwks
What am I missing or wrong? Maybe you will help me with this example spring cloud demo with SSO
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.