1 Star 0 Fork 8

coolhank / yoci-spring-cloud-security-oauth2-demo

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

Spring Cloud Gateway + Spring Oauth 2.0 整合(服务端与资源端分离)

个人开发环境

java环境:Jdk1.8.0_60 (idea 需安装lombok插件)

编译器:IntelliJ IDEA 2019.1

框架:spirng cloud Hoxton + springboot 2.2 + spring oauth 2.0 + spring security 5

一、前言

服务名 注释 描述
yoci-auth 鉴权服务 实现一个简单的基本的 oauth2鉴权服务 使用 jwt token,使用自定义 JwtTokenStore
yoci-api 资源服务 实现简单资源服务,提供简单的 Restful API,通过 gateway调用
yoci-gate 网关服务 使用 spring cloud gateway 实现简单路由,实现统一路由转发

依次运行 yoci-authyoci-gateyoci-api

二、父工程构建

1.pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring-cloud.version>Hoxton.SR1</spring-cloud.version>
    <spring-platform.version>Cairo-SR8</spring-platform.version>
    <alibaba-cloud.version>2.1.1.RELEASE</alibaba-cloud.version>
    <spring-boot.version>2.2.2.RELEASE</spring-boot.version>
</properties>

<modules>
    <module>yoci-auth</module>
    <module>yoci-api</module>
    <module>yoci-gate</module>
</modules>

<!-- 依赖管理,用于管理spring-cloud的依赖 -->
<dependencyManagement>
    <dependencies>
        <!-- spring-boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- spring-io 版本兼容管理 -->
        <dependency>
            <groupId>io.spring.platform</groupId>
            <artifactId>platform-bom</artifactId>
            <version>${spring-platform.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- spring-cloud & alibaba-cloud -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${alibaba-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- lombok 开发小插件 -->
<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.14</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

<!-- maven仓库-依赖声明 -->
<repositories>
    <repository>
        <id>oss</id>
        <name>oss</name>
        <url>https://oss.sonatype.org/content/groups/public</url>
    </repository>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/libs-milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>sonatype-nexus-snapshots</id>
        <name>Sonatype Nexus Snapshots</name>
        <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
    </repository>
</repositories>

三、网关

网关在demo中实现统一路由转发作用,不做安全验证,在实战微服务环境中,也可在gateway网关处实现其提供的相应过滤器进行统一拦截,实现安全验证,此demo为了学习演示方便,采用资源服务器通过远程token校验进行安全验证

1.pom.xml

<artifactId>yoci-gate</artifactId>
<dependencies>
    <!-- spring boot 相关依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <!-- webflux 相关依赖 (spring gateway采用的webflux 无需添加spring-boot-web依赖(会和servlet冲突),) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <!-- spring gateway 相关依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
</dependencies>

2.application.yml

server:
  port: 8082

## gateway
spring:
  application:
    name: yoci-gate
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true               # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
      routes:
        - id: yoci-api
          # uri: lb://yoci-api        # 动态路由方式需要配合eureka、nacos注册中心使用
          uri: http://localhost:8083
          predicates:
            - Path=/api/**
          filters:
            - StripPrefix=1
        - id: yoci-auth
          # uri: lb://yoci-auth       # 动态路由方式需要配合eureka、nacos注册中心使用
          uri: http://localhost:8081
          predicates:
            - Path=/auth/**
          filters:
            - StripPrefix=1

3.启动类

/**
 * 网关主启动类
 * 
 * @author: YoCiyy
 * @date: 2020/6/22
 */
@SpringBootApplication
public class GateBootstrap {
	public static void main(String[] args) {
		SpringApplication.run(GateBootstrap.class, args);
	}
}

四、服务端(鉴权服务 yoci-auth)

1.pom.xml

<artifactId>yoci-auth</artifactId>
<dependencies>
    <!-- spring oauth2.0 (包含了spring security无需单独引入) 相关 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>

    <!-- spring boot 相关依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

</dependencies>

2.application.yml

# 服务端口号
server:
  port: 8081

# 服务名
spring:
  application:
    name: yoci-auth

# actuator
management:
  endpoints:
    web:
      exposure:
        include: "*"

3.启动类

/**
 * auth主启动类
 * 
 * @author: YoCiyy
 * @date: 2020/6/22
 */
@SpringBootApplication
public class AuthBootstrap {
	public static void main(String[] args) {
		SpringApplication.run(AuthBootstrap.class, args);
	}
}

4.java配置类

创建oauth认证服务器配置AuthorizationServerConfig 配置类,继承AuthorizationServerConfigurerAdapter

/**
 * oauth认证服务器配置
 * 
 * @author: YoCiyy
 * @date: 2020/6/22
 */
@Configuration
@AllArgsConstructor
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

	/** 令牌持久化配置 */
	private final TokenStore tokenStore;
	/** 客户端详情服务 */
	private final ClientDetailsService clientDetailsService;
	/** 认证管理器 */
	private final AuthenticationManager authenticationManager;
	/** 授权码服务 */
	private final AuthorizationCodeServices authorizationCodeServices;
	/** jwtToken解析器 */
	private final JwtAccessTokenConverter jwtAccessTokenConverter;

	/**
	 * 客户端详情服务配置 (demo采用本地内存存储)
	 */
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		clients
				// 使用本地内存存储
				.inMemory()
				// 客户端id
				.withClient("client_1")
				// 客户端密码
				.secret(new BCryptPasswordEncoder().encode("123456"))
				// 该客户端允许授权的类型
				.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
				// 该客户端允许授权的范围
				.scopes("all")
				// false跳转到授权页面,true不跳转,直接发令牌
				.autoApprove(false);
	}

	/**
	 * 配置访问令牌端点
	 */
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
		endpoints
				// 认证管理器
				.authenticationManager(authenticationManager)
				// 授权码服务
				.authorizationCodeServices(authorizationCodeServices)
				// 令牌管理服务
				.tokenServices(tokenServices())
				.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
	}

	/**
	 * 配置令牌端点安全约束
	 */
	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) {
		security
				// oauth/check_token公开
				.checkTokenAccess("permitAll()")
				// oauth/token_key 公开密钥
				.tokenKeyAccess("permitAll()")
				// 允许表单认证
				.allowFormAuthenticationForClients();
	}

	/**
	 * 令牌服务配置
	 * 
	 * @return 令牌服务对象
	 */
	public AuthorizationServerTokenServices tokenServices() {
		DefaultTokenServices tokenServices = new DefaultTokenServices();
		tokenServices.setTokenStore(tokenStore);
		tokenServices.setSupportRefreshToken(true);
		// 令牌增强
		TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
		tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));
		tokenServices.setTokenEnhancer(tokenEnhancerChain);
		// 令牌默认有效期2小时
		tokenServices.setAccessTokenValiditySeconds(7200);
		// 刷新令牌默认有效期3天
		tokenServices.setRefreshTokenValiditySeconds(259200);
		return tokenServices;
	}

}

创建Security 安全配置类WebSecurityConfig 继承WebSecurityConfigurerAdapter

/**
 * security 安全相关配置类
 * 
 * @author: YoCiyy
 * @date: 2020/6/22
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	/**
	 * 安全拦截机制
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
				.authorizeRequests()
				// 放行
				.antMatchers("/auth/**")
				.permitAll()
				// 其他请求必须认证通过
				.anyRequest().authenticated()
				.and()
				.formLogin() // 允许表单登录
//                .successForwardUrl("/login-success") //自定义登录成功跳转页
				.and()
				.csrf().disable();

	}

	/**
	 * token持久化配置
	 */
	@Bean
	public TokenStore tokenStore() {
		// 本地内存存储令牌
		return new InMemoryTokenStore();
	}

	/**
	 * 密码加密器
	 */
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	/**
	 * 认证管理器配置
	 */
	@Bean
	@Override
	protected AuthenticationManager authenticationManager() {
		return authentication -> daoAuthenticationProvider().authenticate(authentication);
	}

	/**
	 * 认证是由 AuthenticationManager 来管理的,但是真正进行认证的是 AuthenticationManager 中定义的 AuthenticationProvider,用于调用userDetailsService进行验证
	 */
	@Bean
	public AuthenticationProvider daoAuthenticationProvider() {
		DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
		daoAuthenticationProvider.setUserDetailsService(userDetailsService());
		daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
		daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
		return daoAuthenticationProvider;
	}

	/**
	 * 用户详情服务
	 */
	@Bean
	@Override
	protected UserDetailsService userDetailsService() {
		// 测试方便采用内存存取方式
		InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
		userDetailsService.createUser(User.withUsername("user_1").password(passwordEncoder().encode("123456")).authorities("ROLE_USER").build());
		userDetailsService.createUser(User.withUsername("user_2").password(passwordEncoder().encode("1234567")).authorities("ROLE_USER").build());
		return userDetailsService;
	}

	/**
	 * 设置授权码模式的授权码如何存取,暂时采用内存方式 
	 */
	@Bean
	public AuthorizationCodeServices authorizationCodeServices() {
		return new InMemoryAuthorizationCodeServices();
	}

	/**
	 * jwt token解析器
	 */
	@Bean
	public JwtAccessTokenConverter accessTokenConverter() {

		JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
		// 对称密钥,资源服务器使用该密钥来验证
		converter.setSigningKey("YoCiyy");
		return converter;
	}
}

5.postman测试

采用授权码模式访问测试

获取jwt token:http://localhost:8081/oauth/token

1593327117473

校验jwt token :http://localhost:8081/oauth/check_token

1593327301948

五、资源端(资源服务yoci-api)

1.pom.xml

<artifactId>yoci-api</artifactId>
<dependencies>

    <!-- spring oauth2.0 (包含了spring security无需单独引入) 相关 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>

    <!-- spring boot 相关依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

</dependencies>

2.application.yml

server:
  port: 8083

spring:
  application:
    name: yoci-api

3.启动类

/**
 * 模拟接口启动类
 * 
 * @author: YoCiyy
 * @date: 2020/6/23
 */
@SpringBootApplication
public class ApiBootstrap {
	public static void main(String[] args) {
		SpringApplication.run(ApiBootstrap.class, args);
	}
}

4.java配置类

创建资源服务配置ResourceServerConfig继承ResourceServerConfigurerAdapter

/**
 * 资源服务配置
 * 
 * @author: YoCiyy
 * @date: 2020/6/19
 */
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

	/**
	 * token服务配置
	 */
    @Override
	public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
		resources.tokenServices(tokenServices());
	}

	/**
	 * 路由安全认证配置
	 */
	@Override
	public void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
				// 配置hello打头的路由需要安全认证,order无配置无需认证
				.antMatchers("/hello/**").authenticated()
				.and().csrf().disable();
	}

	/**
	 * jwt token 校验解析器
	 */
	@Bean
	public TokenStore tokenStore() {
		return new JwtTokenStore(accessTokenConverter());
	}

	/**
	 * Token转换器必须与认证服务一致
	 */
	@Bean
	public JwtAccessTokenConverter accessTokenConverter() {
		JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
		accessTokenConverter.setSigningKey("YoCiyy");
		return accessTokenConverter;
	}

	/**
	 * 资源服务令牌解析服务
	 */
	@Bean
	@Primary
	public ResourceServerTokenServices tokenServices() {
        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:8081/oauth/check_token");
        remoteTokenServices.setClientId("client_1");
        remoteTokenServices.setClientSecret("123456");
        return remoteTokenServices;
	}
}

5.postman测试

通过网关路由转发,请求资源服务器

不配置请求头token,直接/order可直接访问成功(在资源服务配置类中,/order打头路由没有配置安全路由)

1593329760740

不配置请求头中的token,访问/hello报401错误

1593329706170

请求头中配置申请到的token,格式 Bearer (申请到的token),访问/hello测试调用资源服务api成功

1593329508452

相关学习资料

demo源码获取

Spring Cloud Gateway 基于 OAuth2.0 的身份认证

Spring Boot Oauth2.0 服务端与资源端分离

Spring Security Oauth2.0学习视频

MIT License Copyright (c) 2020 YoCiyy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

暂无描述 展开 收起
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/coolhank/yoci-spring-cloud-security-oauth2-demo.git
git@gitee.com:coolhank/yoci-spring-cloud-security-oauth2-demo.git
coolhank
yoci-spring-cloud-security-oauth2-demo
yoci-spring-cloud-security-oauth2-demo
master

搜索帮助