diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..4e1fde0 Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md index 93ef2e2..d495a12 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ +2018-4-25 日更新 + +## 新增授权码(authorization_code)模式配置示例 + +尝试访问获取token +http://localhost:8080/oauth/authorize?client_id=aiqiyi&response_type=code&redirect_uri=http://localhost:8081/aiqiyi/qq/redirect + +具体工作原理介绍有空再更新 + +在 springboot2.0 下会有问题,还没有定位到原因,建议 springboot 1.0 下使用 + 2018-4-19 日更新 # springboot 2.0使用spring-security-oauth2的迁移指南 diff --git a/authorization-code/.DS_Store b/authorization-code/.DS_Store new file mode 100644 index 0000000..4e9cb48 Binary files /dev/null and b/authorization-code/.DS_Store differ diff --git a/authorization-code/aiqiyi/.DS_Store b/authorization-code/aiqiyi/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/authorization-code/aiqiyi/.DS_Store differ diff --git a/authorization-code/aiqiyi/pom.xml b/authorization-code/aiqiyi/pom.xml new file mode 100644 index 0000000..2dd9396 --- /dev/null +++ b/authorization-code/aiqiyi/pom.xml @@ -0,0 +1,48 @@ + + + + authorization-code + moe.cnkirito + 1.0.0.RELEASE + + 4.0.0 + + aiqiyi + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter-actuator + + + org.projectlombok + lombok + 1.16.20 + + + + + 1.8 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/authorization-code/aiqiyi/src/main/java/moe/cnkirito/security/oauth2/code/AiqiyiApp.java b/authorization-code/aiqiyi/src/main/java/moe/cnkirito/security/oauth2/code/AiqiyiApp.java new file mode 100644 index 0000000..a1aaed8 --- /dev/null +++ b/authorization-code/aiqiyi/src/main/java/moe/cnkirito/security/oauth2/code/AiqiyiApp.java @@ -0,0 +1,25 @@ +package moe.cnkirito.security.oauth2.code; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +/** + * @author 徐靖峰[OF2938] + * company qianmi.com + * Date 2018-04-25 + */ +@SpringBootApplication +public class AiqiyiApp { + + public static void main(String[] args) { + SpringApplication.run(AiqiyiApp.class, args); + } + + @Bean + RestTemplate restTemplate(){ + return new RestTemplate(); + } + +} diff --git a/authorization-code/aiqiyi/src/main/java/moe/cnkirito/security/oauth2/code/controller/QQCallbackController.java b/authorization-code/aiqiyi/src/main/java/moe/cnkirito/security/oauth2/code/controller/QQCallbackController.java new file mode 100644 index 0000000..c79460b --- /dev/null +++ b/authorization-code/aiqiyi/src/main/java/moe/cnkirito/security/oauth2/code/controller/QQCallbackController.java @@ -0,0 +1,58 @@ +package moe.cnkirito.security.oauth2.code.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author 徐靖峰[OF2938] + * company qianmi.com + * Date 2018-04-25 + */ +@RestController +@Slf4j +public class QQCallbackController { + +// withClient("aiqiyi") +// .authorizedGrantTypes("authorization_code","refresh_token", "implicit") +// .authorities("ROLE_CLIENT") +// .scopes("get_user_info","get_fanslist") +// .secret("secret") +// .redirectUris("http://localhost:8081/aiqiyi/qq/redirect") +// .autoApprove(true) +// .autoApprove("get_user_info") + + @Autowired + RestTemplate restTemplate; + + @RequestMapping("/aiqiyi/qq/redirect") + public String getToken(@RequestParam String code){ + log.info("receive code {}",code); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + MultiValueMap params= new LinkedMultiValueMap<>(); + params.add("grant_type","authorization_code"); + params.add("code",code); + params.add("client_id","aiqiyi"); + params.add("client_secret","secret"); + params.add("redirect_uri","http://localhost:8081/aiqiyi/qq/redirect"); + HttpEntity> requestEntity = new HttpEntity<>(params, headers); + ResponseEntity response = restTemplate.postForEntity("http://localhost:8080/oauth/token", requestEntity, String.class); + String token = response.getBody(); + log.info("token => {}",token); + return token; + } + +} diff --git a/authorization-code/aiqiyi/src/main/resources/application.yml b/authorization-code/aiqiyi/src/main/resources/application.yml new file mode 100644 index 0000000..54b155f --- /dev/null +++ b/authorization-code/aiqiyi/src/main/resources/application.yml @@ -0,0 +1,2 @@ +server: + port: 8081 \ No newline at end of file diff --git a/authorization-code/pom.xml b/authorization-code/pom.xml new file mode 100644 index 0000000..f0f3087 --- /dev/null +++ b/authorization-code/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + moe.cnkirito + authorization-code + 1.0.0.RELEASE + + qq + aiqiyi + + pom + + + org.springframework.boot + spring-boot-starter-parent + 1.5.11.RELEASE + + + + 1.8 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + \ No newline at end of file diff --git a/authorization-code/qq/.DS_Store b/authorization-code/qq/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/authorization-code/qq/.DS_Store differ diff --git a/authorization-code/qq/pom.xml b/authorization-code/qq/pom.xml new file mode 100644 index 0000000..5a0701a --- /dev/null +++ b/authorization-code/qq/pom.xml @@ -0,0 +1,65 @@ + + + + + authorization-code + moe.cnkirito + 1.0.0.RELEASE + + 4.0.0 + + jar + + qq + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.security.oauth + spring-security-oauth2 + 2.3.2.RELEASE + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.projectlombok + lombok + 1.16.20 + + + + + 1.8 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + \ No newline at end of file diff --git a/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/QQApp.java b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/QQApp.java new file mode 100644 index 0000000..890ffa1 --- /dev/null +++ b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/QQApp.java @@ -0,0 +1,18 @@ +package moe.cnkirito.security.oauth2.code; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author 徐靖峰[OF2938] + * company qianmi.com + * Date 2018-04-25 + */ +@SpringBootApplication +public class QQApp { + + public static void main(String[] args) { + SpringApplication.run(QQApp.class, args); + } + +} diff --git a/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/config/MvcConfig.java b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/config/MvcConfig.java new file mode 100644 index 0000000..6dc3ee3 --- /dev/null +++ b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/config/MvcConfig.java @@ -0,0 +1,19 @@ +package moe.cnkirito.security.oauth2.code.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@Configuration +public class MvcConfig extends WebMvcConfigurerAdapter { + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/home").setViewName("home"); + registry.addViewController("/").setViewName("home"); + registry.addViewController("/hello").setViewName("hello"); + registry.addViewController("/login").setViewName("login"); + } + +} diff --git a/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/config/OAuth2ServerConfig.java b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/config/OAuth2ServerConfig.java new file mode 100644 index 0000000..2385256 --- /dev/null +++ b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/config/OAuth2ServerConfig.java @@ -0,0 +1,121 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package moe.cnkirito.security.oauth2.code.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +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.configuration.EnableAuthorizationServer; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; +import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; +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.config.annotation.web.configurers.ResourceServerSecurityConfigurer; +import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; + +/** + * @author Rob Winch + * + */ +@Configuration +public class OAuth2ServerConfig { + + private static final String QQ_RESOURCE_ID = "qq"; + + @Configuration + @EnableResourceServer + protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { + + @Override + public void configure(ResourceServerSecurityConfigurer resources) { + resources.resourceId(QQ_RESOURCE_ID).stateless(false); + } + + @Override + public void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) + .and() + .authorizeRequests() + .antMatchers("/qq/info/**").access("#oauth2.hasScope('get_user_info')") + .antMatchers("/qq/fans/**").access("#oauth2.hasScope('get_fanslist')"); + // @formatter:on + } + + } + + @Configuration + @EnableAuthorizationServer + protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { + +// @Autowired +// private UserApprovalHandler userApprovalHandler; + + @Autowired + @Qualifier("authenticationManagerBean") + private AuthenticationManager authenticationManager; + + @Override + public void configure(ClientDetailsServiceConfigurer clients) throws Exception { + + // @formatter:off + clients.inMemory().withClient("aiqiyi") + .resourceIds(QQ_RESOURCE_ID) + .authorizedGrantTypes("authorization_code","refresh_token", "implicit") + .authorities("ROLE_CLIENT") + .scopes("get_user_info","get_fanslist") + .secret("secret") + .redirectUris("http://localhost:8081/aiqiyi/qq/redirect") + .autoApprove(true) + .autoApprove("get_user_info") + .and() + .withClient("youku") + .resourceIds(QQ_RESOURCE_ID) + .authorizedGrantTypes("authorization_code","refresh_token", "implicit") + .authorities("ROLE_CLIENT") + .scopes("get_user_info","get_fanslist") + .secret("secret") + .redirectUris("http://localhost:8082/youku/qq/redirect"); + // @formatter:on + } + + @Autowired + RedisConnectionFactory redisConnectionFactory; + + @Override + public void configure(AuthorizationServerEndpointsConfigurer endpoints) { + endpoints.tokenStore(new RedisTokenStore(redisConnectionFactory)) + .authenticationManager(authenticationManager).allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST); +// .userApprovalHandler(userApprovalHandler) + } + + @Override + public void configure(AuthorizationServerSecurityConfigurer oauthServer) { + oauthServer.realm(QQ_RESOURCE_ID).allowFormAuthenticationForClients(); + } + + } + + +} diff --git a/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/config/SecurityConfiguration.java b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/config/SecurityConfiguration.java new file mode 100644 index 0000000..397cca1 --- /dev/null +++ b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/config/SecurityConfiguration.java @@ -0,0 +1,74 @@ +package moe.cnkirito.security.oauth2.code.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +@Configuration +@EnableWebSecurity +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Bean + @Override + protected UserDetailsService userDetailsService(){ + InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); + // 创建两个 qq 用户 + manager.createUser(User.withUsername("250577914").password("123456").authorities("USER").build()); + manager.createUser(User.withUsername("920129126").password("123456").authorities("USER").build()); + return manager; + } + +// @Autowired +// public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception { +// auth.inMemoryAuthentication() +// .withUser("250577914").password("123456").authorities("USER").and() +// .withUser("920129126").password("123456").authorities("USER"); +// } + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Bean + PasswordEncoder passwordEncoder(){ + return NoOpPasswordEncoder.getInstance(); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .antMatchers("/", "/home","/login","/oauth/authorize").permitAll() + .anyRequest().authenticated() + .and() + .formLogin() + .loginPage("/login") + .and() + .httpBasic() + .disable() + .exceptionHandling() + .accessDeniedPage("/login?authorization_error=true") + .and() + // TODO: put CSRF protection back into this endpoint + .csrf() + .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")) + .disable(); +// .loginPage("/login") +// .failureUrl("/login?authentication_error=true") +// .httpBasic(); + // @formatter:on + } +} diff --git a/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/endpoint/InMemoryQQDatabase.java b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/endpoint/InMemoryQQDatabase.java new file mode 100644 index 0000000..bee4eb2 --- /dev/null +++ b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/endpoint/InMemoryQQDatabase.java @@ -0,0 +1,34 @@ +package moe.cnkirito.security.oauth2.code.endpoint; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * @author 徐靖峰[OF2938] + * company qianmi.com + * Date 2018-04-25 + */ +public class InMemoryQQDatabase { + + public static Map database; + + static { + database = new HashMap<>(); + database.put("250577914",new QQAccount().qq("250577914").nickName("鱼非渔").level("54")); + database.put("920129126",new QQAccount().qq("920129126").nickName("下一秒升华").level("31")); + + QQAccount qqAccount1 = database.get("250577914"); + qqAccount1.fans(new ArrayList<>()); + for(int i=0;i<5;i++){ + qqAccount1.fans().add(new QQAccount().qq("1000000"+i).nickName("fan"+i).level(i+"") ); + } + + QQAccount qqAccount2 = database.get("920129126"); + qqAccount2.fans(new ArrayList<>()); + for(int i=0;i<3;i++){ + qqAccount2.fans().add(new QQAccount().qq("2000000"+i).nickName("fan"+i).level(i+"") ); + } + } + +} diff --git a/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/endpoint/QQAccount.java b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/endpoint/QQAccount.java new file mode 100644 index 0000000..5571c7d --- /dev/null +++ b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/endpoint/QQAccount.java @@ -0,0 +1,26 @@ +package moe.cnkirito.security.oauth2.code.endpoint; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * @author 徐靖峰[OF2938] + * company qianmi.com + * Date 2018-04-25 + */ +@Data +@Accessors(fluent = true, chain = true) +@EqualsAndHashCode(of = "qq") +@ToString(exclude = "fans") +public class QQAccount { + + private String qq; + private String nickName; + private String level; + private List fans; + +} diff --git a/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/endpoint/QQRestfulApiProviderController.java b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/endpoint/QQRestfulApiProviderController.java new file mode 100644 index 0000000..f88bbcb --- /dev/null +++ b/authorization-code/qq/src/main/java/moe/cnkirito/security/oauth2/code/endpoint/QQRestfulApiProviderController.java @@ -0,0 +1,30 @@ +package moe.cnkirito.security.oauth2.code.endpoint; + +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author 徐靖峰[OF2938] + * company qianmi.com + * Date 2018-04-25 + */ +@RestController +@RequestMapping("/qq") +public class QQRestfulApiProviderController { + + @RequestMapping("/info/{qq}") + public QQAccount info(@PathVariable("qq") String qq){ + return InMemoryQQDatabase.database.get(qq); + } + + @RequestMapping("fans/{qq}") + public List fans(@PathVariable("qq") String qq){ + return InMemoryQQDatabase.database.get(qq).fans(); + } + + + +} diff --git a/authorization-code/qq/src/main/resources/application.yml b/authorization-code/qq/src/main/resources/application.yml new file mode 100644 index 0000000..1a6d88a --- /dev/null +++ b/authorization-code/qq/src/main/resources/application.yml @@ -0,0 +1,9 @@ +server: + port: 8080 + +spring: + redis: + host: 127.0.0.1 + database: 0 + +logging.level.org.springframework.security: DEBUG \ No newline at end of file diff --git a/authorization-code/qq/src/main/resources/templates/hello.html b/authorization-code/qq/src/main/resources/templates/hello.html new file mode 100644 index 0000000..46feef7 --- /dev/null +++ b/authorization-code/qq/src/main/resources/templates/hello.html @@ -0,0 +1,13 @@ + + + + Hello World! + + +

Hello [[${#httpServletRequest.remoteUser}]]!

+
+ +
+ + \ No newline at end of file diff --git a/authorization-code/qq/src/main/resources/templates/home.html b/authorization-code/qq/src/main/resources/templates/home.html new file mode 100644 index 0000000..fe4e8b3 --- /dev/null +++ b/authorization-code/qq/src/main/resources/templates/home.html @@ -0,0 +1,11 @@ + + + + Spring Security Example + + +

Welcome!

+ +

Click here to see a greeting.

+ + \ No newline at end of file diff --git a/authorization-code/qq/src/main/resources/templates/login.html b/authorization-code/qq/src/main/resources/templates/login.html new file mode 100644 index 0000000..a178531 --- /dev/null +++ b/authorization-code/qq/src/main/resources/templates/login.html @@ -0,0 +1,20 @@ + + + + Spring Security Example + + +
+ Invalid username and password. +
+
+ You have been logged out. +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/client-credentials-springboot2/.DS_Store b/client-credentials-springboot2/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/client-credentials-springboot2/.DS_Store differ diff --git a/client-credentials-springboot2/src/main/java/moe/cnkirito/security/oauth2/config/OAuth2ServerConfig.java b/client-credentials-springboot2/src/main/java/moe/cnkirito/security/oauth2/config/OAuth2ServerConfig.java index 5397966..08959e4 100644 --- a/client-credentials-springboot2/src/main/java/moe/cnkirito/security/oauth2/config/OAuth2ServerConfig.java +++ b/client-credentials-springboot2/src/main/java/moe/cnkirito/security/oauth2/config/OAuth2ServerConfig.java @@ -93,8 +93,7 @@ public void configure(AuthorizationServerEndpointsConfigurer endpoints) { @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) { //允许表单认证 - oauthServer.allowFormAuthenticationForClients() - ; + oauthServer.allowFormAuthenticationForClients(); } } diff --git a/client-credentials/.DS_Store b/client-credentials/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/client-credentials/.DS_Store differ diff --git a/pom.xml b/pom.xml index 706ddd6..aafd9e8 100644 --- a/pom.xml +++ b/pom.xml @@ -10,6 +10,7 @@ client-credentials client-credentials-springboot2 + authorization-code pom