美文网首页
微服务 Spring Cloud Alibaba 项目搭建(八、

微服务 Spring Cloud Alibaba 项目搭建(八、

作者: 一介书生独醉江湖 | 来源:发表于2023-07-31 19:24 被阅读0次

    一、oauth 安全认证子模块创建

    1.1、右键项目 - New - Module

    image.png

    1.2、bootstrap.yml

    server:
      port: 9002
      servlet:
        context-path:
    spring:
      application:
        name: oauth
      profiles:
        active: dev           # 运行环境
      freemarker:
        check-template-location: false
        prefer-file-system-access: false
    logging:      # logback 配置
      path: /usr/local/alibaba/logs/${spring.application.name}   # 保存日志文件目录路径
      level: # 日志级别
        org.springframework.web: DEBUG # 配置spring web日志级别
    
    

    1.3、bootstrap-dev.yml

    spring:
      cloud:
        nacos:
          discovery:
            server-addr: 192.168.0.119:8848                  # nacos的访问地址,根据上面准备工作中启动的实例配置
            namespace: 11ba48cc-9931-4760-bf58-7d3e2c99629c   # Nacos test命名空间的ID
          config:
            server-addr: 192.168.0.119:8848                  # nacos的访问地址,根据上面准备工作中启动的实例配置
            namespace: 11ba48cc-9931-4760-bf58-7d3e2c99629c   # Nacos test命名空间的ID
            group: DEFAULT_GROUP                              # 默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置
            file-extension: yml                               # 默认properties
    

    1.4、pom.xml

    <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">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>com.aydan</groupId>
            <artifactId>ali-cloud</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </parent>
    
        <artifactId>oauth</artifactId>
        <packaging>jar</packaging>
    
        <name>oauth</name>
        <url>http://maven.apache.org</url>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>com.aydan</groupId>
                <artifactId>common</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--nacos service discovery client依赖-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <!--nacos config client 依赖-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            </dependency>
            <!-- Java Servlet -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
            </dependency>
    
            <!--导入spring cloud oauth2依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-oauth2</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            
            <!-- Swagger 第三方UI -->
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>knife4j-spring-boot-starter</artifactId>
                <version>1.9.6</version>
            </dependency>
    
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
    

    1.5、OauthApplication.java

    package com.aydan;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.core.env.Environment;
    
    import javax.annotation.PostConstruct;
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    import java.util.TimeZone;
    
    /**
     * @Author ds
     * @Date 2023/7/31
     */
    @SpringBootApplication
    @EnableDiscoveryClient
    public class OauthApplication {
    
        public static void main(String[] args) {
            TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
            // SpringApplication.run(MasterApplication.class, args);
            ConfigurableApplicationContext application = SpringApplication.run(OauthApplication.class, args);
            Environment environment = application.getEnvironment();
            String applicationName = environment.getProperty("spring.application.name");
            String port = environment.getProperty("server.port");
            String contextPath = environment.getProperty("server.servlet.context-path");
            System.out.println("---------------------------------------------------------->");
            System.out.println(" :: ServletInitializer 启动:" + applicationName);
            String localHost;
            try {
                localHost = InetAddress.getLocalHost().getHostAddress();
                System.out.println("\t\t http://" + localHost + ":" + port + "" + contextPath + "");
            } catch (UnknownHostException e) {
                System.out.println("\t\t " + e.getMessage());
                e.printStackTrace();
            }
            System.out.println("<----------------------------------------------------------");
        }
    
        @PostConstruct
        void setDefaultTimezone() {
            TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
        }
    
    }
    
    

    1.6、Nacos配置 oauth-dev.yml

    image.png
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://********:3306/db_name?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
        username: root
        password: ********
        druid:
          initialSize: 100
          minIdle: 100
          maxActive: 300
          maxWait: 50000
      redis:
        database:
        host: 192.168.0.119
        port: 6379
        #密码
        password: ********
        #客户端超时时间单位是毫秒 默认是2000
        timeout: 10000
        #最大空闲数
        maxIdle: 300
        #控制一个pool可分配多少个jedis实例,用来替换上面的redis.maxActive,如果是jedis 2.4以后用该属性
        maxTotal: 1000
        #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
        maxWaitMillis: 1000
        #连接的最小空闲时间 默认1800000毫秒(30分钟)
        minEvictableIdleTimeMillis: 300000
        #每次释放连接的最大数目,默认3
        numTestsPerEvictionRun: 1024
        #逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
        timeBetweenEvictionRunsMillis: 30000
        #是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
        testOnBorrow: true
        #在空闲时检查有效性, 默认false
        testWhileIdle: true
    

    二、使用 Redis 的方式来实现 token 的存储

    添加四个类: OAuthConfig.java、OAuthJwtAccessTokenConverter.java、RedisTokenStoreConfig.java、WebSecurityConfig.java
    

    2.1、OAuthConfig.java

    package config;
    
    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.core.userdetails.UserDetailsService;
    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.token.TokenStore;
    import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
    
    import javax.sql.DataSource;
    
    /**
     * @Author ds
     * @Date 2023/7/31
     */
    @Configuration
    @EnableAuthorizationServer
    public class OAuthConfig extends AuthorizationServerConfigurerAdapter {
    
        @Autowired
        private DataSource dataSource;
    
        @Autowired
        private TokenStore redisTokenStore;
    
        @Autowired
        public PasswordEncoder passwordEncoder;
    
        @Autowired
        public UserDetailsService kiteUserDetailsService;
    
        @Autowired
        private AuthenticationManager authenticationManager;
    
        /**
         * 认证服务器Endpoints配置
         * spring security token的生成方式
         * @param endpoints
         * @throws Exception
         */
        @Override
        public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            // 设置access_token存储器,redis
            endpoints.tokenStore(redisTokenStore)
                    .authenticationManager(authenticationManager)
                    .userDetailsService(kiteUserDetailsService)
                    .accessTokenConverter(accessTokenConverter());
        }
    
        /**
         * AccessToken转换器-定义token的生成方式,这里使用JWT生成token,对称加密只需要加入key等其他信息(自定义)。
         * @return JwtAccessTokenConverter
         */
        @Bean
        public JwtAccessTokenConverter accessTokenConverter() {
            // 用新的jwt转换器
            return new OAuthJwtAccessTokenConverter();
        }
    
        /**
         * client存储方式,此处使用jdbc存储
         * @param clients
         * @throws Exception
         */
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
        }
    
        /**
         * 认证服务器相关接口权限管理
         * @param security
         * @throws Exception
         */
        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            security.allowFormAuthenticationForClients()
                    .checkTokenAccess("isAuthenticated()")
                    .tokenKeyAccess("isAuthenticated()");
        }
    }
    
    

    2.2、OAuthJwtAccessTokenConverter.java

    package config;
    
    import com.aydan.base.GlobalVar;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
    import org.springframework.security.oauth2.common.OAuth2AccessToken;
    import org.springframework.security.oauth2.provider.OAuth2Authentication;
    import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    /**
     * @Author ds
     * @Date 2023/7/31
     */
    public class OAuthJwtAccessTokenConverter extends JwtAccessTokenConverter {
    
        @Override
        public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
            DefaultOAuth2AccessToken defaultOAuth2AccessToken = new DefaultOAuth2AccessToken(accessToken);
            // 设置过期时间
            defaultOAuth2AccessToken.setExpiration(new Date(System.currentTimeMillis() + 1000 * 3600 * 24 * 7)); // 有效期一周
            List<String> authorities = new ArrayList<>();
            // 设置额外用户信息
            User user = ((User) authentication.getPrincipal());
            user.getAuthorities().forEach(authority -> authorities.add(authority.getAuthority()));
            // 将用户信息添加到token额外信息中
            defaultOAuth2AccessToken.getAdditionalInformation().put("username", user.getUsername());
            defaultOAuth2AccessToken.getAdditionalInformation().put("authorities", authorities);
            // 设置秘钥
            super.setSigningKey(GlobalVar.OAUTH_TOKEN_SECRET);
            return super.enhance(defaultOAuth2AccessToken, authentication);
        }
    }
    
    

    2.3、RedisTokenStoreConfig.java

    package config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.security.oauth2.provider.token.TokenStore;
    import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
    
    /**
     * @Author ds
     * @Date 2023/7/31
     */
    @Configuration
    public class RedisTokenStoreConfig {
    
        @Autowired
        private RedisConnectionFactory redisConnectionFactory;
    
        @Bean
        public TokenStore redisTokenStore (){
            return new RedisTokenStore(redisConnectionFactory);
        }
    
    }
    
    

    2.4、WebSecurityConfig.java

    package config;
    
    import org.springframework.context.annotation.Bean;
    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.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * @Author ds
     * @Date 2023/7/31
     */
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        /**
         * 认证管理
         * @return 认证管理对象
         * @throws Exception 认证异常信息
         */
        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
        /**
         * 允许匿名访问所有接口 主要是 oauth 接口
         * @param http HTTP协议安全配置实例
         * @throws Exception 设置异常
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/**")
                    .permitAll();
        }
    
    }
    
    

    2.5、oauth_client 表

    -- oauth_client表
    create table oauth_client_details (
        client_id VARCHAR(256) PRIMARY KEY,
        resource_ids VARCHAR(256),
        client_secret VARCHAR(256),
        scope VARCHAR(256),
        authorized_grant_types VARCHAR(256),
        web_server_redirect_uri VARCHAR(256),
        authorities VARCHAR(256),
        access_token_validity INTEGER,
        refresh_token_validity INTEGER,
        additional_information VARCHAR(4096),
        autoapprove VARCHAR(256)
    );
    INSERT INTO oauth_client_details
        (client_id, client_secret, scope, authorized_grant_types,
        web_server_redirect_uri, authorities, access_token_validity,
        refresh_token_validity, additional_information, autoapprove)
    VALUES
        ('user-client', '$2a$10$o2l5kA7z.Caekp72h5kU7uqdTDrlamLq.57M1F6ulJln9tRtOJufq', 'all',
        'authorization_code,refresh_token,password', null, null, 3600, 36000, null, true);
    
    INSERT INTO oauth_client_details
        (client_id, client_secret, scope, authorized_grant_types,
        web_server_redirect_uri, authorities, access_token_validity,
        refresh_token_validity, additional_information, autoapprove)
    VALUES
        ('order-client', '$2a$10$GoIOhjqFKVyrabUNcie8d.ADX.qZSxpYbO6YK4L2gsNzlCIxEUDlW', 'all',
        'authorization_code,refresh_token,password', null, null, 3600, 36000, null, true);
    

    2.6、sa_user 表

    CREATE TABLE `sa_user` (
      `user_id` varchar(40) NOT NULL,
      `user_name` varchar(20) NOT NULL,
      `passwd` varchar(100) DEFAULT NULL,
      PRIMARY KEY (`user_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    -- 正常数据库密码加密,这里只为演示
    

    2.7、AuthUserService.java

    package com.aydan.user.service;
    
    import com.aydan.business.dao.SaUserDao;
    import com.aydan.business.entity.SaUserEntity;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.userdetails.User;
    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.Component;
    
    import java.util.ArrayList;
    
    /**
     * @Author ds
     * @Date 2023/7/31
     */
    @Slf4j
    @Component
    public class AuthUserService implements UserDetailsService {
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Autowired
        protected SaUserDao saUserDao;
    
    
        /**
         * 根据用户名,取用户详细信息
         *
         * @param username
         * @return
         * @throws UsernameNotFoundException
         */
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            SaUserEntity saUserEntity = saUserDao.getByUserName(username);
            if (saUserEntity == null) {
                throw new UsernameNotFoundException("用户不存在");
            }
            String original = saUserEntity.getPasswd();
            String password = passwordEncoder.encode(original);     // 解密密码
            System.out.println("* ------------------------------------------------------> AuthUserService.loadUserByUsername()");
            System.out.println("* 用户名:" + username);
            System.out.println("* 解密后的密码:" + password);
            System.out.println("* <------------------------------------------------------");
            return new User(username, password, new ArrayList<>());
        }
    }
    
    

    2.8、common中增加sa_user的相关实体类

    image.png
    package com.aydan.business.dao;
    
    import com.aydan.business.entity.SaUserEntity;
    import com.aydan.business.vo.SaUserSearchVo;
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    
    /**
     * @Author ds
     * @Date 2023/8/1
     */
    @Mapper
    public interface SaUserDao extends BaseMapper<SaUserEntity> {
    
        List<SaUserEntity> queryPage(SaUserSearchVo searchVo);
    
        SaUserEntity getById(@Param("userId") String userId);
    
        void removeById(@Param("userId") String userId);
    
        SaUserEntity getByUserName(@Param("userName") String userName);
    
    }
    
    
    package com.aydan.business.entity;
    
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    
    import java.io.Serializable;
    
    /**
     * @Author ds
     * @Date 2023/8/1
     */
    @Data
    @TableName(value = "sa_user")
    @ApiModel(value = "SaUser", description = "用户基本信息")
    public class SaUserEntity implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        /**
         * 用户id
         */
        @TableId
        @ApiModelProperty(value = "用户id", example = "示例:1", notes = "用户id")
        private String userId;
    
        /**
         * 登录名
         */
        @ApiModelProperty(value = "登录名", example = "示例:登录名", notes = "登录名")
        private String userName;
    
        /**
         * 登录密码
         */
        @ApiModelProperty(value = "登录密码", example = "示例:登录密码", notes = "登录密码")
        private String passwd;
    
    }
    
    
    package com.aydan.business.vo;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import org.hibernate.validator.constraints.Length;
    
    import java.io.Serializable;
    
    /**
     * @Author ds
     * @Date 2023/8/1
     */
    @Data
    @ApiModel(value = "SaUserSaveVo", description = "用户基本信息")
    public class SaUserSaveVo implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        /**
         * 用户id
         */
        @Length(max = 40, message = "长度不能超过40个字符")
        @ApiModelProperty(value = "用户id", example = "示例:用户id", notes = "用户id")
        private String userId;
    
        /**
         * 登录名
         */
        @Length(max = 20, message = "长度不能超过20个字符")
        @ApiModelProperty(value = "登录名", example = "示例:登录名", notes = "登录名")
        private String userName;
    
        /**
         * 登录密码
         */
        @Length(max = 100, message = "长度不能超过100个字符")
        @ApiModelProperty(value = "登录密码", example = "示例:登录密码", notes = "登录密码")
        private String passwd;
    }
    
    
    package com.aydan.business.vo;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    
    import javax.validation.constraints.Max;
    import javax.validation.constraints.NotNull;
    import java.io.Serializable;
    
    /**
     * @Author ds
     * @Date 2023/8/1
     */
    @Data
    @ApiModel(value = "SaUserSearchVo", description = "用户基本信息")
    public class SaUserSearchVo implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        /**
         * 当前页数
         */
        @NotNull(message="当前页属性不能为空")
        @ApiModelProperty(value="当前页数", example="1", notes="当前页数")
        private int page;
    
        /**
         * 每页显示记录数
         */
        @Max(value=1000, message="每页显示记录数不能超过1000")
        @ApiModelProperty(value="每页显示记录数", example="10", notes="每页显示记录数")
        private int limit;
    
        /**
         * 要排序的字段
         */
        @ApiModelProperty(value = "要排序的字段", example = "createDt", notes = "要排序的字段")
        private String sidx;
    
        /**
         * 排序方式
         */
        @ApiModelProperty(value = "排序方式", example = "示例:asc/desc", notes = "排序方式")
        private String order;
    
        /**
         * 用户id
         */
        @ApiModelProperty(value = "用户id", example = "示例:1", notes = "用户id")
        private String userId;
    
        /**
         * 登录名
         */
        @ApiModelProperty(value = "登录名", example = "示例:登录名", notes = "登录名")
        private String userName;
    
        /**
         * 登录密码
         */
        @ApiModelProperty(value = "登录密码", example = "示例:登录密码", notes = "登录密码")
        private String passwd;
    
    
    }
    
    
    package com.aydan.business.vo;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import org.hibernate.validator.constraints.Length;
    
    import java.io.Serializable;
    
    /**
     * @Author ds
     * @Date 2023/8/1
     */
    @Data
    @ApiModel(value = "SaUserUpdateVo", description = "用户基本信息")
    public class SaUserUpdateVo implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        /**
         * 用户id
         */
        @Length(max = 40, message = "长度不能超过40个字符")
        @ApiModelProperty(value = "用户id", example = "示例:1", notes = "用户id")
        private String userId;
    
        /**
         * 登录名
         */
        @Length(max = 20, message = "长度不能超过20个字符")
        @ApiModelProperty(value = "登录名", example = "示例:登录名", notes = "登录名")
        private String userName;
    
        /**
         * 登录密码
         */
        @Length(max = 100, message = "长度不能超过100个字符")
        @ApiModelProperty(value = "登录密码", example = "示例:登录密码", notes = "登录密码")
        private String passwd;
    
    }
    
    
    package com.aydan.business.service;
    
    import com.aydan.base.PageBean;
    import com.aydan.business.entity.SaUserEntity;
    import com.aydan.business.vo.SaUserSaveVo;
    import com.aydan.business.vo.SaUserSearchVo;
    import com.aydan.business.vo.SaUserUpdateVo;
    
    /**
     * @Author ds
     * @Date 2023/8/1
     */
    public interface SaUserService {
    
        PageBean<SaUserEntity> queryList(SaUserSearchVo searchVo);
    
        void create(SaUserSaveVo saveVo) throws Exception;
    
        void update(SaUserUpdateVo updateVo) throws Exception;
    
        void logicDelete(String userId);
    
        void switchEnable(String userId, int enabled);
    
        SaUserEntity getById(String userId);
        SaUserEntity getByUserName(String userName);
    
        void removeById(String userId);
    
    }
    
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.aydan.business.dao.SaUserDao">
    
        <!-- 可根据自己的需求,是否要使用 -->
        <resultMap type="com.aydan.business.entity.SaUserEntity" id="saUserMap">
            <result property="userId" column="user_id"/>
            <result property="userName" column="user_name"/>
            <result property="passwd" column="passwd"/>
        </resultMap>
    
        <sql id="Base_Column_List">
            user_id , user_name, passwd</sql>
    
        <sql id="Base_Where">
            <trim prefix="WHERE" prefixOverrides="AND|OR">
                <if test="userId != null">AND `user_id` = #{userId}</if>
                <if test="userName != null">AND `user_name` = #{userName}</if>
                <if test="passwd != null">AND `passwd` = #{passwd}</if>
    
            </trim>
        </sql>
    
        <select id="queryPage" parameterType="com.aydan.business.vo.SaUserSearchVo" resultMap="saUserMap">
            SELECT
            <include refid="Base_Column_List"/>
            FROM sa_user
            <include refid="Base_Where"/>
            <choose>
                <when test="sidx != null and sidx.trim() != ''">
                    order by ${sidx} ${order}
                </when>
                <otherwise>
                    order by user_name desc
                </otherwise>
            </choose>
        </select>
    
        <select id="getById" resultType="com.aydan.business.entity.SaUserEntity">
            select *
            from sa_user
            where `user_id` = #{userId}
        </select>
    
        <select id="getByUserName" resultType="com.aydan.business.entity.SaUserEntity">
            select *
            from sa_user
            where `user_name` = #{userName}
        </select>
    
        <delete id="removeById">
            delete
            from sa_user
            where `user_id` = #{userId}
        </delete>
    
    
    </mapper>
    
    

    2.9、engine 子模块中创建UserServiceImpl.java

    package com.aydan.service.impl;
    
    import com.aydan.base.PageBean;
    import com.aydan.business.dao.SaUserDao;
    import com.aydan.business.entity.SaUserEntity;
    import com.aydan.business.service.SaUserService;
    import com.aydan.business.vo.SaUserSaveVo;
    import com.aydan.business.vo.SaUserSearchVo;
    import com.aydan.business.vo.SaUserUpdateVo;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.github.pagehelper.PageHelper;
    import com.github.pagehelper.PageInfo;
    import org.apache.dubbo.config.annotation.DubboService;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.BeanUtils;
    import org.springframework.transaction.annotation.Transactional;
    
    import javax.annotation.Resource;
    
    /**
     * @Author ds
     * @Date 2023/8/1
     */
    @DubboService
    public class UserServiceImpl extends ServiceImpl<SaUserDao, SaUserEntity> implements SaUserService {
    
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        @Resource
        private SaUserDao saUserDao;
    
        @Override
        public PageBean<SaUserEntity> queryList(SaUserSearchVo searchVo) {
            PageBean<SaUserEntity> pageBean = new PageBean<>();
            try {
                PageHelper.startPage(searchVo.getPage(),searchVo.getLimit());
                PageInfo<SaUserEntity> page = new PageInfo<>(saUserDao.queryPage(searchVo));
                pageBean.setCount(new Long(page.getTotal()).intValue());    // 条数
                pageBean.setLimit(searchVo.getLimit());                     // 设置每页显示记录数
                pageBean.setCurrentPage(searchVo.getPage());                // 设置当前页数
                pageBean.setData(page.getList());                           // 设置数据
                pageBean.setStatus(0);                                      // 设置状态码
                pageBean.setMessage(" 查询完成");                                   // 设置返回信息
            } finally {
                PageHelper.clearPage();
            }
            return pageBean;
        }
    
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void create(SaUserSaveVo saveVo) throws Exception{
            SaUserEntity saUserEntity = new SaUserEntity();
            BeanUtils.copyProperties(saveVo, saUserEntity);
            saUserDao.insert(saUserEntity);
        }
    
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void update(SaUserUpdateVo updateVo) throws Exception{
            SaUserEntity saUserEntity = new SaUserEntity();
            BeanUtils.copyProperties(updateVo, saUserEntity);
            saUserDao.updateById(saUserEntity);
        }
    
        @Override
        public void switchEnable(String userId, int enabled) {
            SaUserEntity saUserEntity = new SaUserEntity();
            saUserEntity.setUserId(userId);
            //saUserEntity.setModifierId(userEntity.getUserId());
            //saUserEntity.setEnabled(enabled);
            saUserDao.updateById(saUserEntity);
        }
    
        @Override
        public void logicDelete(String userId) {
            SaUserEntity saUserEntity = new SaUserEntity();
            saUserEntity.setUserId(userId);
            //saUserEntity.setModifier(userEntity.getId());
            //saUserEntity.setIsDelete(1);
            saUserDao.updateById(saUserEntity);
        }
    
        @Override
        public SaUserEntity getById(String userId) {
            return saUserDao.getById(userId);
        }
    
        @Override
        public SaUserEntity getByUserName(String userName) {
            return saUserDao.getByUserName(userName);
        }
    
        @Override
        public void removeById(String userId) {
            saUserDao.removeById(userId);
        }
    }
    
    

    三、新增api子模块

    3.1、右键项目 - New - Module

    image.png

    3.2、ApiApplication.java

    package com.aydan;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.core.env.Environment;
    
    import javax.annotation.PostConstruct;
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    import java.util.TimeZone;
    
    /**
     * @Author ds
     * @Date 2023/8/1
     */
    @SpringBootApplication
    @EnableDiscoveryClient
    public class ApiApplication {
    
        public static void main(String[] args) {
            TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
            // SpringApplication.run(MasterApplication.class, args);
            ConfigurableApplicationContext application = SpringApplication.run(ApiApplication.class, args);
            Environment environment = application.getEnvironment();
            String applicationName = environment.getProperty("spring.application.name");
            String port = environment.getProperty("server.port");
            String contextPath = environment.getProperty("server.servlet.context-path");
            System.out.println("---------------------------------------------------------->");
            System.out.println(" :: ServletInitializer 启动:" + applicationName);
            String localHost;
            try {
                localHost = InetAddress.getLocalHost().getHostAddress();
                System.out.println("\t\t http://" + localHost + ":" + port + "" + contextPath + "");
            } catch (UnknownHostException e) {
                System.out.println("\t\t " + e.getMessage());
                e.printStackTrace();
            }
            System.out.println("<----------------------------------------------------------");
        }
    
        @PostConstruct
        void setDefaultTimezone() {
            TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
        }
    }
    
    

    3.3、pom.xml

    <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">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>com.aydan</groupId>
            <artifactId>ali-cloud</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </parent>
    
        <artifactId>api</artifactId>
        <packaging>jar</packaging>
    
        <name>api</name>
        <url>http://maven.apache.org</url>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
    
        <dependencies>
    
            <!--集成公共模块-->
            <dependency>
                <groupId>com.aydan</groupId>
                <artifactId>common</artifactId>
                <version>0.0.1-SNAPSHOT</version>
                <exclusions>
                    <exclusion>
                        <groupId>com.alibaba</groupId>
                        <artifactId>druid-spring-boot-starter</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.mybatis.spring.boot</groupId>
                        <artifactId>mybatis-spring-boot-starter</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>com.baomidou</groupId>
                        <artifactId>mybatis-plus-boot-starter</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--nacos service discovery client依赖-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <!--nacos config client 依赖-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            </dependency>
    
            <!-- Java Servlet -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-freemarker</artifactId>
            </dependency>
    
            <!-- 导入spring cloud oauth2依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-oauth2</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
    
            <!--spring cloud+dubbo 依赖-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-dubbo</artifactId>
            </dependency>
    
            <!-- Swagger 第三方UI -->
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>knife4j-spring-boot-starter</artifactId>
                <version>1.9.6</version>
            </dependency>
    
            <!-- SpringCloud Alibaba Sentinel 流量监控控制台 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.22</version>
                <scope>compile</scope>
            </dependency>
    
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <includeSystemScope>true</includeSystemScope>
                        <!-- 是否限制解压缩 -->
                        <executable>false</executable>
                        <mainClass>com.aydan.ApiApplication</mainClass>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>
    
    
    

    3.4、bootstrap.yml

    server:
      port: 9003
      servlet:
        context-path: /api
      tomcat:
        uri-encoding: utf-8
    spring:
      application:
        name: api
      profiles:
        active: dev           # 运行环境
      freemarker:
        check-template-location: false
        prefer-file-system-access: false
    logging:      # logback 配置
      path: /usr/local/alibaba/logs/${spring.application.name}   # 保存日志文件目录路径
      level: # 日志级别
        org.springframework.web: DEBUG # 配置spring web日志级别
    
    

    3.5、bootstrap-dev.yml

    spring:
      cloud:
        nacos:
          discovery:
            server-addr: 192.168.0.119:8848        # nacos的访问地址,根据上面准备工作中启动的实例配置
            namespace: 11ba48cc-9931-4760-bf58-7d3e2c99629c   # Nacos test命名空间的ID
          config:
            server-addr: 192.168.0.119:8848        # nacos的访问地址,根据上面准备工作中启动的实例配置
            namespace: 11ba48cc-9931-4760-bf58-7d3e2c99629c   # Nacos test命名空间的ID
            group: DEFAULT_GROUP  # 默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置
            file-extension: yml   # 默认properties
    
    

    3.6、nacos 配置 bootstrap-dev.yml

    image.png
    spring:
      redis:
        database:
        host: 192.168.0.119
        port: 6379
        password: 01810bd1983b496684a4c13ab2580cd1
        timeout: 5000
    security:
      oauth2:
        client:
          client-id: user-client
          client-secret: user-secret-8888
          user-authorization-uri: http://localhost:9002/oauth/authorize
          access-token-uri: http://localhost:9002/oauth/token
        resource:
          id: user-client
          user-info-uri: user-info
        authorization:
          check-token-access: http://localhost:9002/oauth/check_token
    dubbo:
      consumer:
        timeout: 36000
      protocol:
        # dubbo 协议
        name: dubbo
        # 配置本机内网地址
        host: 127.0.0.1
        # dubbo 协议端口( -1 表示自增端口,从 20880 开始)
        port: -1
      registry:
        # 挂载到 Spring Cloud 注册中心
        address: spring-cloud://192.168.0.119
      cloud:
        # 订阅服务提供方的应用列表,订阅多个服务提供者使用 "," 连接
        subscribed-services: engine
    rocketmq:
      name-server: 192.168.0.119:9876
      producer:
        # 小坑:必须指定group
        group: ali-group
    

    3.7 ResourceServerConfig.java

    package com.aydan.config;
    
    import com.aydan.component.ApiAuthenticationEntryPoint;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    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;
    import org.springframework.security.oauth2.provider.token.TokenStore;
    import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
    
    @Configuration
    @EnableResourceServer
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    
        @Value("${security.oauth2.client.client-id}")
        private String clientId;
    
        @Value("${security.oauth2.client.client-secret}")
        private String secret;
    
        @Value("${security.oauth2.authorization.check-token-access}")
        private String checkTokenEndpointUrl;
    
        @Autowired
        private RedisConnectionFactory redisConnectionFactory;
    
        @Autowired
        private ApiAuthenticationEntryPoint apiAuthEnticationEntryPoint;
    
        @Bean
        public TokenStore redisTokenStore() {
            return new RedisTokenStore(redisConnectionFactory);
        }
    
        @Bean
        public RemoteTokenServices tokenService() {
            RemoteTokenServices tokenService = new RemoteTokenServices();
            tokenService.setClientId(clientId);
            tokenService.setClientSecret(secret);
            tokenService.setCheckTokenEndpointUrl(checkTokenEndpointUrl);
            return tokenService;
        }
    
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) {
            resources.authenticationEntryPoint(apiAuthEnticationEntryPoint);
        }
    }
    
    

    3.8 ApiAuthenticationEntryPoint.java

    package com.aydan.component;
    
    import com.alibaba.fastjson.JSON;
    import com.aydan.base.RestResponse;
    import com.aydan.dict.ResultCode;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
    import org.springframework.security.web.AuthenticationEntryPoint;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * @Author ds
     * @Date 2023/8/1
     */
    @Component("apiAuthenticationEntryPoint")
    public class ApiAuthenticationEntryPoint implements AuthenticationEntryPoint {
    
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
            Throwable cause = authException.getCause();
            response.setHeader("Content-Type", "application/json;charset=UTF-8");
            RestResponse restResponse = RestResponse.instance();
            if (!(cause instanceof InvalidTokenException)) {
                restResponse.setResult(ResultCode.TOKEN_LOSE);
            } else {
                restResponse.setResult(ResultCode.TOKEN_INVALID);
            }
            try {
                response.getWriter().write(JSON.toJSONString(restResponse));
            } catch (IOException e) {
                System.err.println("\n* ############################### token认证失败 ###############################");
                System.err.println("* token认证结果:" + cause.getMessage());
                System.err.println("* 异常信息:" + e.getMessage());
                System.err.println("* ");
                e.printStackTrace();
            }
        }
    }
    
    

    3.9 UserBlockHandler.java

    package com.aydan.config;
    
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
    import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
    import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
    import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
    import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
    import com.alibaba.fastjson.JSON;
    
    import java.util.HashMap;
    
    /**
     * @Author ds
     * @Date 2023/8/1
     */
    public class UserBlockHandler {
    
        public static String handleException(BlockException ex) {
            HashMap<String, Object> map = new HashMap<>();
            if (ex instanceof FlowException) {
                map.put("code", -1);
                map.put("msg", "系统限流,请稍等");
            } else if (ex instanceof DegradeException) {
                map.put("code", -2);
                map.put("msg", "降级了");
            } else if (ex instanceof ParamFlowException) {
                map.put("code", -3);
                map.put("msg", "热点参数限流");
            } else if (ex instanceof SystemBlockException) {
                map.put("code", -4);
                map.put("msg", "系统规则(负载/...不满足要求)");
            } else if (ex instanceof AuthorityException) {
                map.put("code", -5);
                map.put("msg", "授权规则不通过");
            }
            return JSON.toJSONString(map);
        }
    
        public static String handleError() {
            HashMap<String, Object> map = new HashMap<>();
            map.put("code", 500);
            map.put("msg", "系统异常");
            return JSON.toJSONString(map);
        }
    }
    
    

    3.10 UserController.java

    package com.aydan.business.controller;
    
    
    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.alibaba.fastjson.JSON;
    import com.aydan.business.entity.SaUserEntity;
    import com.aydan.business.service.SaUserService;
    import com.aydan.config.UserBlockHandler;
    import org.apache.dubbo.config.annotation.Reference;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @Author ds
     * @Date 2023/8/1
     */
    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Reference
        private SaUserService saUserService;
    
        /**
         * 获取用户信息
         */
        @PostMapping("/userInfo")
        public String userInfo() {
            String userName = SecurityContextHolder.getContext().getAuthentication().getName();
            return JSON.toJSONString(saUserService.getByUserName(userName));
        }
    
        /**
         * 测试流控规则
         */
        @PostMapping("/testFlow")
        @SentinelResource(value = "user-testFlow",
                blockHandlerClass = UserBlockHandler.class, //对应异常类
                blockHandler = "handleException",  //只负责sentinel控制台配置违规
                fallback = "handleError",   //只负责业务异常
                fallbackClass = UserBlockHandler.class)
        public String testFlow() {
            SaUserEntity saUserEntity = saUserService.getByUserName("admin");
            return JSON.toJSONString(saUserEntity);
        }
    
        /**
         * 测试降级规则
         */
        @PostMapping("/testDegrade")
        @SentinelResource(value = "user-testDegrade",
                blockHandlerClass = UserBlockHandler.class, //对应异常类
                blockHandler = "handleException",  //只负责sentinel控制台配置违规
                fallback = "handleError",   //只负责业务异常
                fallbackClass = UserBlockHandler.class)
        public String testDegrade() {
            SaUserEntity saUserEntity = saUserService.getByUserName("admin");
            return JSON.toJSONString(saUserEntity);
        }
    }
    
    

    3.12 获取token

    *   假设咱们在一个 web 端使用,grant_type 是 password,表明这是使用 OAuth2 的密码模式。
    *   username=admin 和 password=123456 就相当于在 web 端登录界面输入的用户名和密码,我们在认证服务端配置中固定了用户名是 admin 、密码是 123456,而线上环境中则应该通过查询数据库获取。
    *   scope=all 是权限有关的,在认证服务的 OAuthConfig 中指定了 scope 为 all 。
    *   Authorization 要加在请求头中,格式为 Basic 空格 base64(clientId:clientSecret),这个微服务客户端的 client-id 是 user-client,client-secret 是 user-secret-8888,将这两个值通过冒号连接,并使用 base64 编码(user-client:user-secret-8888)之后的值为 dXNlci1jbGllbnQ6dXNlci1zZWNyZXQtODg4OA==,可以通过 https://www.sojson.com/base64.html在线编码获取。
    
    
    POST http://localhost:9002/oauth/token
    Authorization: Basic dXNlci1jbGllbnQ6dXNlci1zZWNyZXQtODg4OA==
    
    image.png
    image.png
    # 返回JSON:
    {
        "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2OTE1Njc4OTEsImp0aSI6IjRmMGM0NjhjLTkzODktNDRhZC1hMTM5LWMyOWMyNTA4M2QyZCIsImF1dGhvcml0aWVzIjpbXSwiY2xpZW50X2lkIjoidXNlci1jbGllbnQiLCJ1c2VybmFtZSI6ImFkbWluIn0.MWpUvmzLk7u-PG-LiN0Y--M3iExpi-7WITWBeAfeRdI",
        "token_type": "bearer",
        "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiI0ZjBjNDY4Yy05Mzg5LTQ0YWQtYTEzOS1jMjljMjUwODNkMmQiLCJleHAiOjE2OTA5OTkwOTEsImp0aSI6Ijg5Yjc0ZDYxLTY5MTktNDM2Ni1hOTNiLTFkM2QxNTk4NjA2OCIsImF1dGhvcml0aWVzIjpbXSwiY2xpZW50X2lkIjoidXNlci1jbGllbnQiLCJ1c2VybmFtZSI6ImFkbWluIn0.9p1pwj7vz1CPdlZCOB2a7w47CBrikRNz-zTAoCtXGaA",
        "expires_in": 604688,
        "scope": "all",
        "username": "admin",
        "authorities": [],
        "jti": "4f0c468c-9389-44ad-a139-c29c25083d2d"
    }
    
    access_token : 用户的token;
    token_type : bearer
    refresh_token : 用这个值换取新的token
    expires_in : token 的过期时间(秒)
    scope :client的作用域
    username : 用户名
    authorities :client的权限,不能为null
    jti : jwt的唯一身份标识,避免重复
    

    3.13 刷新token

    token 过期后,用 refresh_token 换取 access_token
    一般都会设置 access_token 的过期时间小于 refresh_token 的过期时间,以便在 access_token 过期后,不用用户再次登录的情况下,获取新的 access_token。
    
    POST http://localhost:9002/oauth/token
    Authorization Basic dXNlci1jbGllbnQ6dXNlci1zZWNyZXQtODg4OA==
    
    image.png
    image.png
    # 返回JSON:
    {
        "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2OTE1NjkxNzQsImp0aSI6ImM1OTY0MTYzLTZmOGEtNDNjOS05ODM2LWM1YzM2MjE1NTg5OSIsImF1dGhvcml0aWVzIjpbXSwiY2xpZW50X2lkIjoidXNlci1jbGllbnQiLCJ1c2VybmFtZSI6ImFkbWluIn0.NLOwVkQkBQJSNEmTpoG1YIPSH4KoS3K8C25FA04vDjo",
        "token_type": "bearer",
        "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiJjNTk2NDE2My02ZjhhLTQzYzktOTgzNi1jNWMzNjIxNTU4OTkiLCJleHAiOjE2OTA5OTkwOTEsImp0aSI6Ijg5Yjc0ZDYxLTY5MTktNDM2Ni1hOTNiLTFkM2QxNTk4NjA2OCIsImF1dGhvcml0aWVzIjpbXSwiY2xpZW50X2lkIjoidXNlci1jbGllbnQiLCJ1c2VybmFtZSI6ImFkbWluIn0.SGkHsv8EtSJXDFJUw1TMyXS0do9CC-ZsWwU9eH3inn8",
        "expires_in": 604799,
        "scope": "all",
        "username": "admin",
        "authorities": [],
        "jti": "c5964163-6f8a-43c9-9836-c5c362155899"
    }
    

    3.14 请求获取当前登录用户信息接口

    POST http://localhost:8008/api/user/userInfo
    Authorization bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2OTE1NzM3MDIsImp0aSI6IjI5Zjg4YjJhLTJmMmYtNGU4ZS1hZjkyLTllNGFiMmFmOGQ5OSIsImF1dGhvcml0aWVzIjpbXSwiY2xpZW50X2lkIjoidXNlci1jbGllbnQiLCJ1c2VybmFtZSI6ImFkbWluIn0.oRNoTK-eG08RnyiZyFun8BrTkVe-IqqGOXj3wrXZK2U
    
    image.png
    #  如果token为空或者错误返回对应信息
    
    image.png
    参考:
    https://www.jianshu.com/p/4fd45fb565eb
    
    

    相关文章

      网友评论

          本文标题:微服务 Spring Cloud Alibaba 项目搭建(八、

          本文链接:https://www.haomeiwen.com/subject/jralpdtx.html