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

2023-07-31  本文已影响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

上一篇 下一篇

猜你喜欢

热点阅读