六一儿童节 全网最全的微服务+Outh2套餐,你确定不来试一试?(入门到精通,附源码)满足你的味蕾需要(二)

news2024/11/24 23:11:31

咱们废话不多说,直接开干!!!

目录

一、项目目录

二、Token

三、授权服务器oauth

1.pom

2.application

3.OauthApp启动类

4.DiyUserDetails

5.MyUserDetailService

6.KeyPairController

7.TokenConfig

8.WebSecurityConfig

9.ResourceServerConfig

10.AuthorizationServerConfig

11.授权码模式说明 与 创建数据表

12.测试

(1)获取授权码

(2)获取令牌 

(3)检查令牌

(4)刷新令牌

四、user-service模块与feign模块

五、gateway模块 资源服务器


一、项目目录

feign:远程接口调用

Gateway:资源服务器

Oauth2:授权服务器 

user-service: 普通资源

二、Token

对于Token采用非对称加密,因此到 java 的 bin 目录下打开 cmd,执行以下命令,生成 jwt.jks

keytool -genkey -alias jwt -keyalg RSA -keystore jwt.jks

将其复制到 oauth2 resource 目录下,

三、授权服务器oauth

 

1.pom

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jwt token -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-jose</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-resource-server</artifactId>
        </dependency>
        <!--springboot_redis 缓存 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.white.feign</groupId>
            <artifactId>feign</artifactId>
            <version>1.0</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.white</groupId>
            <artifactId>common</artifactId>
            <version>1.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

2.application

server:
  port: 8101
  servlet:
    context-path: /uaa
spring:
  application:
    name: oauth-service
  datasource:
    url: jdbc:mysql://localhost:3306/pay_system?useUnicode=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 12345
  main:
    allow‐bean‐definition‐overriding: true
    allow-circular-references: true
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        dashboard: localhost:8080
feign:
  sentinel:
    enabled: true

3.OauthApp启动类

@SpringBootApplication
@EnableFeignClients(basePackages = "com.white.feign.client")
@EnableDiscoveryClient
public class OauthApp
{
    public static void main( String[] args )
    {
        SpringApplication.run(OauthApp.class,args);
    }
}

4.DiyUserDetails

package com.white.oauth2.model;

import com.white.feign.model.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class DiyUserDetails extends User implements UserDetails {
    private String username;
    private String password;

    private List<GrantedAuthority> authorities;//授权的
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return 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;
    }
}

5.MyUserDetailService

这里的UserFeign是在feign模块下定义的

package com.white.oauth2.service;

import com.white.feign.client.UserFeign;
import com.white.feign.model.User;
import com.white.oauth2.model.DiyUserDetails;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 作用:
 * @author: white文
 * @time: 2023/5/23 11:00
 */
@Slf4j
@Service
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    UserFeign userFeign;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("********开始loadUserByUsername********");
        User user = userFeign.findUser_ByUsername(username);
        if (user==null) throw new UsernameNotFoundException(username);
        List<GrantedAuthority> grantedAuthorities = AuthorityUtils
                .commaSeparatedStringToAuthorityList(user.getIdentity());
        DiyUserDetails details=new DiyUserDetails();
        details.setUsername(username);
        details.setPassword(user.getPassword());
        details.setAuthorities(grantedAuthorities);
        log.info("查询到user为"+user.getUsername()+" 密码"+user.getPassword());
        return details;
    }
}

6.KeyPairController

package com.white.oauth2.controller;

import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.security.KeyPair;

import java.security.interfaces.RSAPublicKey;
import java.util.Map;

/**
 * 获取RSA公钥接口
 */
@RestController
public class KeyPairController {

    @Autowired
    private KeyPair keyPair;

    @GetMapping("/rsa/publicKey")
    public Map<String, Object> getKey() {
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAKey key = new RSAKey.Builder(publicKey).build();
        return new JWKSet(key).toJSONObject();
    }

}

7.TokenConfig

package com.white.oauth2.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;

import java.security.KeyPair;

@Configuration
public class TokenConfig {
    public static String KEY="white";

    @Bean
    public TokenStore tokenStore(){
        return new JwtTokenStore(jwtAccessTokenConverter());   //  jwt令牌存储方案
    }

    /**
     * 使用非对称加密算法对token签名
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setKeyPair(keyPair());
        return converter;
    }

    /**
     * 从classpath下的密钥库中获取密钥对(公钥+私钥)
     */
    @Bean
    public KeyPair keyPair() {
        KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
                new ClassPathResource("jwt.jks"), "white1".toCharArray());
        KeyPair keyPair = factory.getKeyPair(
                "jwt", "white1".toCharArray());
        return keyPair;
    }
}

8.WebSecurityConfig

package com.white.oauth2.config;

import com.white.oauth2.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailService myUserDetailService;

    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 这里要对以下路径放行
                .antMatchers("/oauth/**","/login/**","/logout/**","/rsa/publicKey")
                .permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().permitAll()
                .and()
                .csrf().disable()
                .httpBasic().disable() // 禁用弹出式认证框
        ;
    }
}

9.ResourceServerConfig

package com.white.oauth2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
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.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Autowired
    TokenStore tokenStore;
    public String RESOURCE_ID="USER";

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId(RESOURCE_ID)
                .tokenStore(tokenStore)
                .stateless(true);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        //设置需要进行保护的资源路径,默认的情况下是保护资源服务的全部路径
        http
                .authorizeRequests().anyRequest()
                .authenticated()
                .and()
                // 因为查询数据库中的user,用的是feign模块下的UserFeign远程接口调用
                //      对应的就是user路径,所以需要对user路径放行
                .requestMatchers()
                .antMatchers("/user/**")
                .and()
                .formLogin().permitAll()
                //关闭跨域伪造检查
                .and().csrf().disable()
                //把session设置为无状态,意思是使用了token,那么session不再做数据的记录
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

10.AuthorizationServerConfig

package com.white.oauth2.config;

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.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.*;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import javax.sql.DataSource;
import java.util.Arrays;
import java.util.List;

/**
 * @AuthorizationServerConfig.java的作用:认证服务器配置
 * @author: white文
 * @time: 2023/5/22 1:02
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    ClientDetailsService clientDetailsService;
    @Autowired
    JwtAccessTokenConverter accessTokenConverter;
    @Autowired
    TokenStore tokenStore;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;

    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        services.setClientDetailsService(clientDetailsService);
        services.setSupportRefreshToken(true);
        services.setTokenStore(tokenStore);
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.<TokenEnhancer>asList(accessTokenConverter));
        services.setTokenEnhancer(tokenEnhancerChain);
        services.setAccessTokenValiditySeconds(7200);
        services.setRefreshTokenValiditySeconds(259200);
        return services;
    }


    @Bean
    public ClientDetailsService clientDetailsService(DataSource dataSource) {
        ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        ((JdbcClientDetailsService) clientDetailsService).setPasswordEncoder(passwordEncoder);
        return clientDetailsService;
    }

    //  配置令牌的访问端点
    @Bean
    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
        //设置授权码模式的授权码如何存取
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    /*
     * 1 用来配置客户端详情服务
     * */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService);
    }

    /*
     * 2 配置令牌(token)的访问端点和令牌服务
     * */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager)
                .authorizationCodeServices(authorizationCodeServices)
                .tokenServices(tokenServices())
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);
    }

    /*
     * 3 配置令牌端点的安全约束
     *   授权服务安全配置:配置哪些路径放行(检查token的路径要放行)
     * */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("permitAll()")   //对应/oauth/check_token ,路径公开
                .tokenKeyAccess("permitAll()")  // 当使用JwtToken且使用非对称加密时,资源服务用于获取公钥而开放的,这里指这个 endpoint完全公开
                .allowFormAuthenticationForClients(); //允许客户端进行表单身份验证,使用表单认证申请令牌
    }
}

11.授权码模式说明与创建数据表

在这里,授权码模式是基于数据库的,而不是基于内存的,如果基于内存需要写死,这不符合灵活性的要求,所以上面的授权码认证都是基于数据库的,而在上面的application我们已经指定数据库的地址,接下来在指定的数据库中 创建两个数据表 就行,oauth会自动到数据库中找到指定两个数据表名称,并对其进行操作。

CREATE TABLE `oauth_client_details` (
  `client_id` VARCHAR(256) CHARACTER SET utf8 NOT NULL COMMENT '客户端唯一标识ID',
  `resource_ids` VARCHAR(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '客户端所能访问的资源id集合',
  `client_secret` VARCHAR(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '客户端访问密匙',
  `scope` VARCHAR(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '客户端申请的权限范围',
  `authorized_grant_types` VARCHAR(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '客户端授权类型',
  `web_server_redirect_uri` VAR`pay_system`CHAR(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '客户端的重定向URI',
  `authorities` VARCHAR(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '客户端所拥有的权限值',
  `access_token_validity` INT(11) DEFAULT NULL COMMENT '客户端access_token的有效时间(单位:秒)',
  `refresh_token_validity` INT(11) DEFAULT NULL,
  `additional_information` VARCHAR(4096) CHARACTER SET utf8 DEFAULT NULL COMMENT '预留的字段',
  `autoapprove` VARCHAR(256) CHARACTER SET utf8 DEFAULT NULL COMMENT '是否跳过授权(true是,false否)',
  PRIMARY KEY (`client_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='客户端授权表'

CREATE TABLE `oauth_code` (
`create_time` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
`code` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`authentication` BLOB NULL,
INDEX `code_index`(`code`) USING BTREE
) ENGINE = INNODB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;

并且新增一条oauth_client_details表的测试数据:client_secret的明文:111

client_idresource_idsclient_secret
123USER$2a$10$1fAQjm5L.1a52uYklwiIMOKgZpye2ctD6Wv/V1Er8LWh1uyv1wRDG
scopeauthorized_grant_typesweb_server_redirect_uriauthoritiesaccess_token_validity
allauthorization_code,refresh_tokenhttp://localhost:10000null7200
refresh_token_validityadditional_informationautoapprove
nullnulltrue

12.测试

到这里,授权服务器就做好了,我们可以进行测试,注意:在数据表中的测试数据跟请求的链接相关:

(1)获取授权码

  • 输入以下地址(该地址的相关信息跟数据表必须保持一致),自动跳转到login路径下

http://localhost:8101/uaa/oauth/authorize?client_id=123&response_type=code&scop=all&redirect_uri=http://localhost:10000

  • 输入用户名和密码,这里是指你自己的微服务中的用户模块,输入后会通过远程调用UserFeign中指定的服务模块,其下的指定接口。也就是说,在做授权服务器outh2之前,你自己得用user模块,做一个简单的接口即可,查询数据库中指定的用户名
  • 登录成功后就会跳转到指定的重定向路径,并在其尾部有着code参数,即授权码

 

(2)获取令牌 

  •  接下来将授权码代入该地址,来 获取令牌 token

 这里的access_token是我们去请求资源时使用的token,而refresh_token只有在我们需要刷新token的时候才用得到。

(3)检查令牌

  • 可以拿着access_token值去以下地址 检查令牌 ,得到令牌中包含的数据

http://localhost:8101/uaa/oauth/check_token?token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiVVNFUiJdLCJ1c2VyX25hbWUiOiIxMTEiLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNjg1NjI5MTU4LCJhdXRob3JpdGllcyI6WyJhZG1pbiJdLCJqdGkiOiJjMlVWSHhPekR6TjFvd3pDMjJRazQwZEktTFEiLCJjbGllbnRfaWQiOiIxMjMifQ.eNpZ9hjAP8MpWIVYzlVeBYhqAbBI9MU5yH8m1kc8EpnCERJtR9cdTbe-1YtqYDFrpgMYpxU2qW8OQDXr74FKj75CCB6Ik-411sGU91Ue7PSa_GKDWujT-0eJavDmDPGRKxS1lhgNdXL1BXGgS38miSa_tNnDoPOx_bydte-Mhi9m9PGBPCyF3taXXV_ARyzBXu183S5Dmv8B_CBNrAk6o7AJPBBBDyNq_puIzR_-HviOHVVsfb1-4qk8wXinS8dZMSJGycay4DKIS7PX8So1IWdXbr4l6SEddFQpnUJ70Af-zNtsFoWUIw_udv4YUZjSlW0IrjqEpXmv2rkGjYMlbQ

 

(4)刷新令牌

  •  当令牌过期时,拿着refresh_token去以下地址 刷新令牌,即可拿到新的令牌token

http://localhost:8101/uaa/oauth/token?grant_type=refresh_token&refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiVVNFUiJdLCJ1c2VyX25hbWUiOiIxMTEiLCJzY29wZSI6WyJhbGwiXSwiYXRpIjoicjhrWWZEcjFDWTFQS0Y2RkZqWTAwMUNia29ZIiwiZXhwIjoxNjg1NzA2NzQyLCJhdXRob3JpdGllcyI6WyJhZG1pbiJdLCJqdGkiOiJhNjNGVkV4N3RHX194UXJDQi05YnBmUWxWakUiLCJjbGllbnRfaWQiOiIxMjMifQ.arUqGU9gpyjZ3g4RsaJDtHHq7jDUgjTfdHwpzdWydM4v7kmvusYb_E9NV7It9GkcRwdpFZBYELaUgM2VIbmon6pMC1TE7LZXb44anSRcUYI8OfiYoSQ8XiJlY8CgNC9wrspWLkw4fXypGUUDUSY6yVS3l_8-kkVi0-EirBFVzNq0rBjlWr1mhGdHZib7JLqPfAdIqC0MDYhXgv4v0ikthkTjz1iDQEDVpJYpx9QXmITnxXCxFtKTSNluzv7M8gJJaJophV1jGF4A6Q8Kt2U_dmxRd07AUSb4dCyik_LOhATPhYYSp9aP7DLnF9bU0u_3_ocp90dxXy3GJwRLQrQ-rQ&client_id=123&client_secret=111

 

 

四、user-service模块与feign模块

由于user-service模块跟feign模块没有涉及到oauth2,也没有导入相关依赖包。

user-service模块作为一个普通的资源模块,feign模块也只是远程调用了user-service模块中的根据用户名查询用户信息给上面的outh2模块而已。

所以,这不是该文章的重点,故不做展示。

五、gateway模块 资源服务器

到此,我们的授权管理器已经结束了,资源服务器在实际开发有两种实现方式:

(1)gateway做网关转发,不做资源服务器,由各个微服务模块自己去做资源服务器;

(2)gateway做网关转发并且做资源服务器。

前者方案使得每一个微服务模块都需要导入oauth2相关依赖,并且做处理,过于繁琐且耦合高。

所以本文章在接下来会采用后者方案进行介绍,也就是文章的重点,并且会介绍到如何解决通过gateway去认证授权,跳转到oauth2认证授权后,跳转不回或重定向不到gatway的bug。

至于我们的gateway模块,会放在下一个文章进行介绍,文章地址将在评论区中展示。

最后,祝大家六一儿童节快乐~~~~~,谁还不是一个宝宝呢!!!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/599420.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LNMP架构

LNMP架构 一、LNMP架构原理二、LNMP部署1、安装 Nginx 服务1.安装依赖包2.创建运行用户3.编译安装4.优化路径5.添加 Nginx 系统服务 2、安装 MySQL 服务1.安装Mysql环境依赖包2.创建运行用户3.编译安装4.修改mysql 配置文件5.更改mysql安装目录和配置文件的属主属组6.设置路径环…

电子模块|压力传感器模块HX711---硬件介绍

电子模块|压力传感器模块HX711---硬件介绍与C51&&STM32驱动 实物照片模块简介模块特点 硬件模拟输入供电电源时钟选择串口通讯复位和断电HX711相关部分的 PCB 设计 实物照片 模块简介 HX711是一款专为高精度称重传感器而设计的24位A/D转换器芯片。与同类型其它芯片相比…

后端接口调式工具

后端接口调式工具 目录概述需求&#xff1a; 设计思路实现思路分析1.Postman2.Swagger 文档测试工具3.Sniff 文档测试工具4.APIpost 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardne…

【SCADA】启动KingSCADA运行系统,提示加载报警库服务失败?

大家好&#xff0c;我是雷工&#xff01; 今天启动KingSCADA时&#xff0c;发现无法运行&#xff0c;提示“加载 报警库服务 失败”&#xff0c;现将问题排查及解决问题的过程记录如下。 一、问题描述&#xff1a; 1、提示如下图&#xff1a; 2、信息窗口提示&#xff1a; …

性能测试从零开始落地实施全过程指南之性能测试计划怎么写?

目录 前言 一、测试背景 二、测试目的 三、测试范围 四、术语约定 五、环境说明 六、需求分析 七、测试策略 八、准备工作 九、组织架构 十、风险分析 十一、交付清单 十二、阶段进度 前言 最近有些同学找我咨询关于性能测试计划相关的问题&#xff0c;原因是他们…

《C++ list的模拟实现》

本文主要介绍list容器的模拟实现 文章目录 1、迭代器正向迭代器类反向迭代器类 2、push_back尾插函数3、 push_front头插函数4、 insert插入函数5、erase删除函数6、pop_front函数7、pop_back函数8、 构造函数9、 拷贝构造函数10、 list赋值重载函数11、clear12、 析构函数程序…

AI注册流程

1、首先需要有一个OpenAI账号&#xff0c;如果有方法的&#xff0c;就可以自己先注册一下。如果没有方法的&#xff0c;还有一个付费版本的可以备选&#xff0c;亲测可用。 2、注册建议使用谷歌账号关联登录&#xff0c;最方便。微软账号太慢了&#xff0c;也可以使用。注册使用…

SAP-MM库存进销存报表

1、总览&#xff1a; 事务代码MB5B是查询选择期间之内的收发存报表&#xff1b; 其中&#xff0c;收、发为汇总选择期间的收、发信息&#xff0c;存为选择期间的期初、期末库存数据&#xff1b;我们也可以用该报表查询历史上某一天的库存&#xff0c;但注意有一些限制条件。 …

【Selenium】提高测试爬虫效率:Selenium与多线程的完美结合

前言 使用Selenium 创建多个浏览器&#xff0c;这在自动化操作中非常常见。 而在Python中&#xff0c;使用 Selenium threading 或 Selenium ThreadPoolExecutor 都是很好的实现方法。 应用场景&#xff1a; 创建多个浏览器用于测试或者数据采集&#xff1b;使用Selenium…

Region Proposal Network (RPN) 架构详解

动动发财的小手&#xff0c;点个赞吧&#xff01; 简介 如果您正在阅读这篇文章[1]&#xff0c;那么我假设您一定听说过用于目标检测的 RCNN 系列&#xff0c;如果是的话&#xff0c;那么您一定遇到过 RPN&#xff0c;即区域提议网络。如果您不了解 RCNN 系列&#xff0c;那么我…

Github copilot的详细介绍,竞品比对分析,效率使用方法总结。

Copilot介绍&#xff0c;与竞品对比 Copilot是GitHub和OpenAI合作开发的一款人工智能代码助手&#xff0c;它可以根据用户输入的注释和代码片段&#xff0c;自动生成高质量的代码。Copilot使用了OpenAI的GPT模型&#xff0c;可以学习和理解大量的代码库和文档&#xff0c;从而…

javascript基础十三:说说 typeof 与 instanceof 区别?

一、typeof typeof 操作符返回一个字符串&#xff0c;表示未经计算的操作数的类型 举个粟子&#xff1a; typeof 1 number typeof 2 string typeof undefined undefined typeof false boolean typeof Symbol() symbol typeof null object typeof [] object typeof {} object…

TCP传输性能的关键因素除了流量控制,还有这些!

TCP网络通信基本原理 文章目录 TCP网络通信基本原理TCP效率&#xff08;滑动窗口&#xff09;流量控制拥塞控制延时应答捎带应答 面向字节流异常情况分析总结UDP/TCP特性与不同应用场景 TCP效率&#xff08;滑动窗口&#xff09; 滑动窗口&#xff1a;在TCP通信协议下&#xf…

【UnityShader入门精要】【总结记录】【第二章-2】

☀️博客主页&#xff1a;CSDN博客主页 &#x1f4a8;本文由 萌萌的小木屋 原创&#xff0c;首发于 CSDN&#x1f4a2; &#x1f525;学习专栏推荐&#xff1a;面试汇总 ❗️游戏框架专栏推荐&#xff1a;游戏实用框架专栏 ⛅️点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd;&a…

1901-2021年1km分辨率逐月最高气温栅格数据(全国/分省)

气温数据是我们最常用的气象指标之一&#xff0c;之前我们给大家分享过来源于国家青藏高原科学数据中心提供的1901-2021年1km分辨率逐月平均气温栅格数据&#xff08;可查看之前的文章获悉详情&#xff09;&#xff01; 本次我们分享的同样是来自国家青藏高原科学数据中心的高…

【探索】在 JavaScript 中使用 C 程序

JavaScript 是个灵活的脚本语言&#xff0c;能方便的处理业务逻辑。当需要传输通信时&#xff0c;我们大多选择 JSON 或 XML 格式。 但在数据长度非常苛刻的情况下&#xff0c;文本协议的效率就非常低了&#xff0c;这时不得不使用二进制格式。 去年的今天&#xff0c;在折腾…

Redis中的整数集合(IntSet)

Redis节省内存的两个优秀设计思想&#xff1a;一个是使用连续的内存空间&#xff0c;避免内存碎片开销&#xff1b;二个是针对不同长度的数据&#xff0c;采用不同大小的元数据&#xff0c;以避免使用统一大小的元数据&#xff0c;造成内存空间的浪费。IntSet便具备以上两个设计…

160套小程序源码

源码列表如下&#xff1a; AppleMusic (知乎日报) 微信小程序 d artand 今日更新求职招聘类 医药网 口碑外卖点餐 城市天气 外卖小程序 定位天气 家居在线 微信小程序-大好商城&#xff0c;wechat-weapp 微信小程序的掘金信息流 微信跳一跳小游戏源码 微票源码-demo 急救应急处…

MyBatis- plus

实战总结 1.批量插入性能 1.批量插入性能差的原因 使用saveBatch()方法时&#xff0c; MySQL JDBC驱动在默认情况下会无视executeBatch()语句&#xff0c;把我们期望批量执行的一组sql语句拆散&#xff0c;一条一条地发给MySQL数据库&#xff0c;批量插入实际上是单条插入&a…

2023企业真实性能测试常见面试题分析

简述性能测试流程&#xff1f; 1.分析性能需求。挑选用户使用最频繁的场景来测试&#xff0c;比如&#xff1a;登陆&#xff0c;搜索&#xff0c;下单等等。确定性能指标&#xff0c;比如&#xff1a;事务通过率为100%&#xff0c;TOP99%是5秒&#xff0c;最大并发用户为1000人…