1、创建一个父项目
依赖不选
创建好后会只有有一个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 https://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.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.butcher</groupId>
<artifactId>springcloudoauth2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloudoauth2</name>
<description>springcloudoauth2 project</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
我们需要修改一下版本号,因为我是以我当前的项目作为背景的,我的项目使用了alibaba的2.2.6版本。
所以将pom修改为:
<?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 https://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.3.2.RELEASE</version>
<relativePath/>
</parent>
<groupId>cn.butcher</groupId>
<artifactId>springcloudoauth2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloudoauth2</name>
<description>springcloudoauth2 project</description>
<!-- 打包方式为pom-->
<packaging>pom</packaging>
<properties>
<java.version>11</java.version>
<spring.boot>2.3.2.RELEASE</spring.boot>
<spring.cloud>Hoxton.SR9</spring.cloud>
</properties>
<dependencies>
<!-- 因为基本上后面子模块都需要用到web,所以直接在父里面引-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!--管理springcloud依赖,后续子模块就不用写版本号了-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2、使用maven创建认证服务器
创建一个认证服务器authentication-service
创建包和主启动类
package cn.butcher;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author 谭熙
* @version 1.0
* @date 2021/10/30 9:51
* @description
*/
@SpringBootApplication
public class AuthenticationApplication {
public static void main(String[] args) {
SpringApplication.run(AuthenticationApplication.class,args);
}
}
创建配置文件application.yml
配置端口
server:
port: 8001
在这个认证模块的pom.xml中加入oauth2的依赖
<?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">
<parent>
<artifactId>springcloudoauth2</artifactId>
<groupId>cn.butcher</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>authentication-service</artifactId>
<dependencies>
<!--oauth2依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
</dependencies>
</project>
PS:如果maven爆红了,刷新也没用,请清楚idea缓存并重启idea尝试
3、编写认证配置
接下来就是编写认证有关的了,因为这是由spring实现的一套oauth2,是基于spring security的
按住ctrl+鼠标左键点进去,其实会发现这里有很多自动配置,管理了很多依赖
第一层,发现是security和oauth2的整合
点击security进入第二层
再继续点
到这思考,可不可以直接使用spring security实现的oauth2捏,后面我们在尝试,这里稍微埋点坑。
创建auth包,这个包下全部是关于认证配置的
所以根据spring security的习惯,我们需要先编写一个自己UserDetails,将来的用户信息全部封装到这里面。
package cn.butcher.auth;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author 谭熙
* @version 1.0
* @date 2021/10/30 10:30
* @description
*/
public class MyUserDetail implements UserDetails {
private String username;
private String password;
private String perms;
public MyUserDetail() {
}
public MyUserDetail(String username, String password, String perms) {
this.username = username;
this.password = password;
this.perms = perms;
}
// 获取权限集合,这里我们自己定义权限编写的规则,通过逗号分隔权限
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Stream.of(perms.split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
// 获取密码,返回当前密码
@Override
public String getPassword() {
return this.password;
}
// 获取用户名,返回当前用户名
@Override
public String getUsername() {
return this.username;
}
// 账户是否没过期
@Override
public boolean isAccountNonExpired() {
return true;
}
// 账户是否未锁定
@Override
public boolean isAccountNonLocked() {
return true;
}
// 凭证是否没过期
@Override
public boolean isCredentialsNonExpired() {
return true;
}
// 是否启用此用户
@Override
public boolean isEnabled() {
return true;
}
}
配置security,配置密码加密器,后面会用到。放行登录,如果登录都不放行,那怎么认证?
package cn.butcher.auth;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author 谭熙
* @version 1.0
* @date 2021/10/30 10:45
* @description
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 密码加密,security所有的密码都需要经过此加密器加密才能使用
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
// 认证管理器
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
// http请求相关配置
@Override
protected void configure(HttpSecurity http) throws Exception {
// 关闭csrf
http.csrf().disable()
// 认证所有请求,将所有请求放行,因为我们使用oauth2进行认证的
.authorizeRequests()
.anyRequest().permitAll()
// 允许表单登录便于用户填写认证信息
.and()
.formLogin()
// 允许登出
.and()
.logout();
}
}
配置用户认证服务,在security接收到用户的登录信息时,会自动调用这里的方法进行验证,这个验证的逻辑需要我们自己实现。
package cn.butcher.auth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
/**
* @author 谭熙
* @version 1.0
* @date 2021/10/30 10:53
* @description
*/
@Service
public class MyUserDetailService implements UserDetailsService {
// 这是在SecurityConfig中配置的密码加密,这里自动导入
@Autowired
private PasswordEncoder passwordEncoder;
// security在获取到用户名后会自动调用这个方法进行认证,我们只需要实现逻辑
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 如果登录的用户是butcher 或者 tanxi ,
// 就说明用户存在,并返回此用户详细信息,否则返回null
// 这里的用户信息还可以更多
if (username.equals("butcher") || username.equals("tanxi")){
return new MyUserDetail(
username,
passwordEncoder.encode(username),
"sys:read,sys:write");
}
return null;
}
}
总要有个地方存放token,所以需要配置token存储的位置,这里可以选择将token放在内存、数据库、redis等地方。。
package cn.butcher.auth;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
/**
* @author 谭熙
* @version 1.0
* @date 2021/10/30 11:04
* @description
*/
@Configuration
public class TokenConfig {
@Bean
public TokenStore tokenStore(){
// 这里还可以配置很多token存储的地方
// JdbcTokenStore、JwtTokenStore、RedisTokenStore...
// 我这里就直接放在内存中了,不过需要注意的是,当上线用户量激增的时候,放在内存中可能会出大事情
return new InMemoryTokenStore();
}
}
既然用到了oauth2,那肯定要进行oauth2的配置,比如设置token的存活时间,刷新token的存活时间等
package cn.butcher.auth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
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.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
/**
* @author 谭熙
* @version 1.0
* @date 2021/10/30 11:09
* @description
*/
@Configuration
@EnableAuthorizationServer
public class Oauth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
PasswordEncoder passwordEncoder;
// 配置客户端认证
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 去内存里找已认证的客户端
clients.inMemory()
// 客户端id ==> AppID
.withClient("bt-client-1")
// 客户端密码 ==> AppSecret
.secret(passwordEncoder.encode("bt123"))
// 允许这个客户端访问的资源为sale-resources,这个等配置资源服务器的时候会用到
.resourceIds("sale-resources")
// 授权类型,四大种嘛 依次为授权码、密码、客户端、简单。
// 最后那个是刷新token,在token即将过期的时候刷新token拿到新的token
.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
// 作用域范围,这也是我们自定的,将我们的应用划分作用域范围,确保这个客户端只能请求固定范围内的资源
.scopes("sale")
// 是否自动统一授权,设置为false,就是需要用户点击同意或者不同意
.autoApprove(true)
// 用户同意后跳转的地址是,这个地址后面会携带一个code,这个code,用来换取token
.redirectUris("http://www.baidu.com");
// 还可以继续and()配置其他客户端
}
@Autowired
TokenStore tokenStore;
@Autowired
private ClientDetailsService clientDetailsService;
// 配置token认证服务
@Bean
public AuthorizationServerTokenServices tokenServices(){
// DefaultTokenServices是AuthorizationServerTokenServices的一个默认实现类
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
// 设置客户端认证服务,就和我们前面写的MyUserDetailService的作用差不多
// 帮我们拿得到的客户端id去验证密码
// 这个认证服务有两个实现类,一个是基于内存的,一个是基于jdbc的
// 当我们需要去数据库中拿到客户端密码比较,就可以用jdbc的
defaultTokenServices.setClientDetailsService(clientDetailsService);
// 是否支持刷新token
defaultTokenServices.setSupportRefreshToken(true);
// 设置token要存储的位置
defaultTokenServices.setTokenStore(tokenStore);
// 设置token的有效存活时间
defaultTokenServices.setAccessTokenValiditySeconds(300);
// 设置刷新token的有效存活时间
defaultTokenServices.setRefreshTokenValiditySeconds(1500);
return defaultTokenServices;
}
// 在security中配置的认证管理器
@Autowired
AuthenticationManager authenticationManager;
// 将认证管理器、认证码服务、token服务组合
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints){
// 认证管理器
endpoints.authenticationManager(authenticationManager)
// 认证码服务
.authorizationCodeServices(new InMemoryAuthorizationCodeServices())
// token服务
.tokenServices(tokenServices())
// 允许请求token的方式
.allowedTokenEndpointRequestMethods(HttpMethod.POST);
}
// 放行与认证有关的接口,如果认证的接口都不放,那么何谈认证
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()")
// 允许表单认证客户端
.allowFormAuthenticationForClients();
}
}
如果都按照上面配置了,那么就可以进行测试了,一般都是用postman测嘛,我们先不管拿到token后如何获取其他服务的资源,我们先要拿到token,检查token是否有效,刷新token,这里没问题了,咱们再继续
4、测试
启动认证服务
PS: 如果启动爆红
有可能是java版本太高了,我用的11,用8就不会报。
在加一个vm参数:–add-opens java.base/java.lang=ALL-UNNAMED
再启动就可以了
1、授权码模式
打卡浏览器请求:http://localhost:8001/oauth/authorize?client_id=bt-client-1&response_type=code&scope=sale&redirect_uri=http://www.baidu.com
注意这里有四个参数:
- client_id ==》 客户端id,就是在Oauth2Config那你配置的客户端id
- response_type==》响应类型,我们期望能给咱返回一个授权码,用于请求真正的token
- scope ==》 作用域,同样是Oauth2Config里定好的,验证客户端想要请求的作用域我们有没有给它设置
- redirect_uri ==》 重定向的地址,注意这里也是你在Oauth2Config写好的,这个不匹配也不行,重定向后会携带一个参数code就是授权码
第一次会要求登录,用户名密码就是你在MyUserDetailService那里配置的。
登录成功后:
拿到授权码,打开postman
发送post请求:http://localhost:8001/oauth/token
携带以下5个参数
- client_id
- client_secret 这里是Oauth2Config那里配置的这个客户端的密匙
- grant_type
- code 将授权码加在此处
- redirect_uri
响应结果
{
"access_token": "bc492e36-eb02-4bc2-9619-e66041da6acd",
"token_type": "bearer",
"refresh_token": "8a38b119-a0d1-4cdb-a844-797ecd5e0af9",
"expires_in": 299,
"scope": "sale"
}
- access_token 认证的token,请求资源的时候将这个带上即可
- token_type token的类型
- refresh_token 可以通过它刷新token,拿到新的token,原来的会失效
- expires_in 在几秒后过期
- scope 作用域
既然可以获取token那么我们测试一下这个token是否可用。
使用postman请求:http://localhost:8001/oauth/check_token
,带上参数token以及它的值
在我打字的这段时间,上次请求的token已经过期了,我们刷新一下token
使用postman请求:http://localhost:8001/oauth/token
并带上四个参数
- client_id
- client_secret
- grant_type 注意这里的类型是refresh_token
- refresh_token
拿到了新的token,再去检查token
token在有效期内,咱么成功拿到了用户信息
{
"aud": [
"sale-resources"
],
"user_name": "butcher",
"scope": [
"sale"
],
"active": true,
"exp": 1635575837,
"authorities": [
"sys:read",
"sys:write"
],
"client_id": "bt-client-1"
}
2、密码模式
这种就简单一些了,不需要授权码,将用户密码一起放在参数里发出去
请求地址:http://localhost:8001/oauth/token
参数:
- client_id
- client_secret
- grant_type == 》注意这里是password
- username
- password
3、客户端模式
这个更简单了,用户名密码都不用填
请求地址:http://localhost:8001/oauth/token
参数:
- client_id
- client_secret
- grant_type == 》注意这里是client_credentials
4、简单模式
这个直接在浏览器发请求就能得到:http://localhost:8001/oauth/authorize?client_id=bt-client-1&response_type=token&scope=sale&redirect_uri=http://www.baidu.com
请求地址:http://localhost:8001/oauth/authorize
参数: - client_id
- response_type ==》返回类型写token
- scope
- redirect_uri
5、编写一个资源
创建一个新的子模块sale-service
作为我们众多服务中的一个服务,依然使用maven创建即可。
创建配置文件,修改端口
server:
port: 8002
创建包和启动类
package cn.butcher;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author 谭熙
* @version 1.0
* @date 2021/10/30 14:50
* @description
*/
@SpringBootApplication
public class SaleApplication {
public static void main(String[] args) {
SpringApplication.run(SaleApplication.class,args);
}
}
创建一个controller
package cn.butcher.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @author 谭熙
* @version 1.0
* @date 2021/10/30 14:52
* @description
*/
@RestController
public class SaleController {
@GetMapping("/order")
public Map<String,Object> getOrder(){
Map<String,Object> data = new HashMap<>();
data.put("status",200);
data.put("msg","获取订单信息成功");
data.put("data",new String[]{"我是订单信息1","我是订单信息2"});
return data;
}
}
启动服务,尝试请求/order
接口
请求成功,接下来将它配置为资源
引入oauth2依赖
<?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">
<parent>
<artifactId>springcloudoauth2</artifactId>
<groupId>cn.butcher</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sale-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
</dependencies>
</project>
编写配置,创建auth包
首先是security的配置
package cn.butcher.auth;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* @author 谭熙
* @version 1.0
* @date 2021/10/30 15:01
* @description 主要是放行所有请求,因为我们是需要oauth2来认证了
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.anyRequest()
.permitAll();
}
}
配置为资源服务器
package cn.butcher.auth;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
/**
* @author 谭熙
* @version 1.0
* @date 2021/10/30 15:03
* @description
*/
@Configuration
@EnableResourceServer
public class Oauth2Config extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
// 请求认证服务器认证,但这么做并不好,请求多了以后,认证服务器压力山大
RemoteTokenServices tokenServices = new RemoteTokenServices();
// 设置请求的地址
tokenServices.setCheckTokenEndpointUrl("http://localhost:8001/oauth/check_token");
// 设置客户端id
tokenServices.setClientId("bt-client-1");
// 设置客户端密码
tokenServices.setClientSecret("bt123");
// 设置资源名字,注意这个资源名字和认证服务器中的Oauth2Config那配置的资源名称是对应的
resources
.resourceId("sale-resources")
.tokenServices(tokenServices);
}
@Override
public void configure(HttpSecurity http) throws Exception {
// 检查是否有正确的作用域
http.csrf().disable()
.authorizeRequests()
.antMatchers("/**")
.access("#oauth2.hasScope('sale')");
}
}
OK,我们再次请求这个/order
接口
这时就提示未授权了,因为我们没有token
我们需要在请求头中加入token信息
注意格式为:Authorization=token类型+空格+token
6、小结
这只是一个简单的演示,真正使用我们应该是在数据库获取redis中存储token信息,并且资源服务器去确认token的时候应该不用每次都去认证服务器请求才是,所以还在继续改进中。
找个时间填一下上面提到的一个坑,就是
也就是说,这种用法要过期了,在下一版本中会将security从springcloud中移除。
所以其实我们可以研究一下,springcloud oauth2到底用了security的什么依赖?
经过我的测试,其实只用到了一个,那就是oauth2的自动配置
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
也就是说其实我们并不需要springcloud的依赖,那么,我们的pom.xml可以变为
父pom
<?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 https://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.3.2.RELEASE</version>
<relativePath/>
</parent>
<modules>
<module>authentication-service</module>
<module>sale-service</module>
</modules>
<groupId>cn.butcher</groupId>
<artifactId>springcloudoauth2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloudoauth2</name>
<description>springcloudoauth2 project</description>
<!-- 打包方式为pom-->
<packaging>pom</packaging>
<properties>
<java.version>11</java.version>
<spring.boot>2.3.2.RELEASE</spring.boot>
<spring.oauth2>2.1.2.RELEASE</spring.oauth2>
</properties>
<dependencies>
<!-- 因为基本上后面子模块都需要用到web,所以直接在父里面引-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<!--oauth2依赖-->
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>${spring.oauth2}</version>
</dependency>
</dependencies>
</project>
子模块完全不用引
<?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">
<parent>
<artifactId>springcloudoauth2</artifactId>
<groupId>cn.butcher</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>authentication-service</artifactId>
</project>
<?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">
<parent>
<artifactId>springcloudoauth2</artifactId>
<groupId>cn.butcher</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sale-service</artifactId>
</project>
经测试,代码不变,运行正常。