satoken+ gateway网关统一鉴权 初版

这篇具有很好参考价值的文章主要介绍了satoken+ gateway网关统一鉴权 初版。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一:感谢大佬

本博客内容 参考了satoken官网实现,satoken官网地址:
https://sa-token.cc/doc.html#/micro/gateway-auth

二:项目层级介绍

  1. jinyi-gateway 网关服务
  2. jinyi-user-service 用户服务
    2.1 jinyi-user-api
    2.2 jinyi-user-client
    2.3 jinyi-user-provider
  3. jinyi-common 通用服务,定义了一些统一返回类,全局常量(R等)
    项目层级关系截图:
    satoken+ gateway网关统一鉴权 初版
    satoken+ gateway网关统一鉴权 初版

三:项目具体介绍

3.1jinyi-gateway 网关服务

3.1.1 pom.xml
parent标签里只是指明了springboot springcloud springcloud-alibaba等版本信息和通用的像lombok等通用的类。

<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/maven-v4_0_0.xsd">
    <parent>
        <artifactId>jinyi-up-project</artifactId>
        <groupId>com.jinyi.up</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>jinyi-gateway</artifactId>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <alibaba.nacos.version>2.1.0</alibaba.nacos.version>
        <jinyi-up.version>1.0.0</jinyi-up.version>
        <sa-token.version>1.34.0</sa-token.version>
    </properties>

    <dependencies>
        <!--Spring Cloud & Alibaba-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <exclusions>
                <!--Sa-Token 权限认证(Reactor响应式)-->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 注册中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <!-- 配置中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--通用基础common-->
        <dependency>
            <groupId>com.jinyi.up</groupId>
            <artifactId>jinyi-common-base</artifactId>
            <version>${jinyi-up.version}</version>
        </dependency>
        <!-- Sa-Token 权限认证(Reactor响应式集成), 在线文档:http://sa-token.dev33.cn/ -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-reactor-spring-boot-starter</artifactId>
            <version>${sa-token.version}</version>
        </dependency>
        <!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-dao-redis-jackson</artifactId>
            <version>${sa-token.version}</version>
        </dependency>
        <!-- 提供Redis连接池 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>com.jinyi.up</groupId>
            <artifactId>jinyi-user-client</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.jinyi.up</groupId>
            <artifactId>jinyi-user-api</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

核心maven依赖

<!-- Sa-Token 权限认证(Reactor响应式集成), 在线文档:https://sa-token.cc -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-reactor-spring-boot-starter</artifactId>
    <version>1.34.0</version>
</dependency>
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-dao-redis-jackson</artifactId>
    <version>1.34.0</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

config包中类:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableAsync
@RefreshScope
public class ExecutorConfig {
    @Value("${executor.corePoolSize:4}")
    private Integer corePoolSize;

    @Value("${executor.queueCapacity:1000}")
    private Integer queueCapacity;

    @Value("${executor.maxPoolSize:6}")
    private Integer maxPoolSize;

    @Value("${executor.keepAliveSeconds:30}")
    private Integer keepAliveSeconds;

    /**
     * 线程池参数定义
     * @return
     */
    @Bean
    public ThreadPoolTaskExecutor AsyncThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix("async-task-executor-");
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setMaxPoolSize(maxPoolSize);
        //线程大于coreSize,多余线程数超过30s则销毁
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 设置拒绝策略,调用当前线程执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;

import java.util.stream.Collectors;

/**
 * gateway是基于WebFlux的一个响应式组件,HttpMessageConverters不会像Spring Mvc一样自动注入,需要我们手动配置
 *
 */
@Configuration
public class HttpMessageConvertersConfigure {
    @Bean
    @ConditionalOnMissingBean
    public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
        return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
    }
}

其中最核心的SaTokenConfigures类

import cn.dev33.satoken.config.SaTokenConfig;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.web.server.ServerWebExchange;

@Configuration
public class SaTokenConfigures {

    //需要放行的接口[白名单]
    private static final String[] PERMITURL = new String[]{
            "/user-api/jinyiUser/accountLogin"
    };

    // 注册 Sa-Token全局过滤器
    @Bean
    public SaReactorFilter getSaServletFilter() {
        return new SaReactorFilter()
                // 拦截地址
                .addInclude("/**")
                // 开放地址【白名单】
//                .addExclude(PERMITURL)
                // 鉴权方法:每次访问进入
                .setAuth(obj -> {
                    // 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
//                  SaRouter.match("/**", "/account-service/account/userLogin", r -> StpUtil.checkLogin());
                    SaRouter.match("/**")
                            .notMatch("/user-api/jinyiUser/accountLogin",
                                    "/**/swagger-resources/**", "/**/webjars/**",
                                    "/**/swagger-ui.html/**",
                                    "/**/doc.html/**", "/**/error",
                                    "/**/favicon.ico").check(r -> StpUtil.checkLogin());
                    // 权限认证 -- 不同模块, 校验不同权限
                      SaRouter.match("/jinyiUser/**", r -> StpUtil.checkRole("admin"));
//                    SaRouter.match("/user-api/jinyiUser/**", r -> StpUtil.checkRole("admin"));
//                    SaRouter.match("/jinyiUser/**", r -> StpUtil.checkPermission("system"));
//                    SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
//                    SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));

                    // ...
                })
                // 异常处理方法:每次setAuth函数出现异常时进入
                .setError(e -> {
                    // 设置错误返回格式为JSON
                    ServerWebExchange exchange = SaReactorSyncHolder.getContext();
                    exchange.getResponse().getHeaders().set("Content-Type", "application/json; charset=utf-8");
                    //登录或者权限相关的resp json 都是在下面的代码里封装返回的
                    return SaResult.error(e.getMessage());
                })

                .setBeforeAuth(obj -> {
                    // ---------- 设置跨域响应头 ----------
                    SaHolder.getResponse()
                            // 允许指定域访问跨域资源
                            .setHeader("Access-Control-Allow-Origin", "*")
                            // 允许所有请求方式
                            .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
                            // 有效时间
                            .setHeader("Access-Control-Max-Age", "3600")
                            // 允许的header参数
                            .setHeader("Access-Control-Allow-Headers", "*");

                    // 如果是预检请求,则立即返回到前端
                    SaRouter.match(SaHttpMethod.OPTIONS).free(r -> System.out.println("--------OPTIONS预检请求,不做处理")).back();
                });
    }

    @Bean
    @Primary
    public SaTokenConfig getSaTokenConfigPrimary() {
        SaTokenConfig config = new SaTokenConfig();
        config.setTokenName("token");             // token名称 (同时也是cookie名称)
        config.setTimeout(30 * 24 * 60 * 60);       // token有效期,单位s 默认30天
        config.setActivityTimeout(-1);              // token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
        config.setIsConcurrent(true);               // 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
        config.setIsShare(true);                    // 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
        config.setTokenStyle("uuid");               // token风格
        config.setIsLog(false);                     // 是否输出操作日志
        return config;
    }
}

exception包GlobalException类

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import com.jinyi.up.common.base.result.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
public class GlobalException {
    
    @ExceptionHandler
    public R handlerException(Exception e) {
        e.printStackTrace();
        // 不同异常返回不同状态码
        R r = null;
        if (e instanceof NotLoginException) {	// 如果是未登录异常
            NotLoginException ee = (NotLoginException) e;
            log.error("登录异常:{}",e.getMessage());
            R.failed(ee.getMessage());
        }
        else if(e instanceof NotRoleException) {		// 如果是角色异常
            NotRoleException ee = (NotRoleException) e;
            R.failed("无此角色:" + ee.getRole());
        }
        else if(e instanceof NotPermissionException) {	// 如果是权限异常
            NotPermissionException ee = (NotPermissionException) e;
            R.failed("无此权限:" + ee.getMessage());
        }
//        else if(e instanceof DisableLoginException) {	// 如果是被封禁异常
//            R.failed("账号被封禁:" + e.getDisableTime() + "秒后解封");
//        }
        else {	// 普通异常, 输出:500 + 异常信息
            R.failed();
        }
        // 返回给前端
        return r;
    }

}

service包中

import cn.dev33.satoken.stp.StpInterface;
import com.google.common.collect.Lists;
import com.jinyi.up.common.base.result.R;
import com.jinyi.up.feignclient.UserProvideFeignClient;
import com.jinyi.up.user.vo.JinyiRoleVO;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Component
public class StpInterfaceImpl implements StpInterface {

    @Resource
    private UserProvideFeignClient userFeignClient;

    @Resource
    @Qualifier(value = "AsyncThreadPoolTaskExecutor")
    ThreadPoolTaskExecutor executor;

    /**
     * 返回指定账号id所拥有的权限码集合
     *
     * @param loginId   账号id
     * @param loginType 账号类型
     * @return 该账号id具有的权限码集合
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        // 返回此 loginId 拥有的权限列表,没有设置权限表。此处为伪代码
        List<String> strs = new ArrayList<>();
        strs.add("system");
        return strs;
    }

    /**
     * 返回指定账号id所拥有的角色标识集合
     *
     * @param loginId   账号id
     * @param loginType 账号类型
     * @return 该账号id具有的角色标识集合
     */
    @SneakyThrows
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        List<String> result = Lists.newArrayList();
        CompletableFuture<R> AsyncResp = CompletableFuture.supplyAsync(() -> {
            return userFeignClient.getUserRoleByUserId((Long) loginId);
        }, executor);
        R<List<JinyiRoleVO>> resp = AsyncResp.get();
        if (R.isSuccess(resp) && !CollectionUtils.isEmpty(resp.getData())) {
            result = resp.getData().stream().map(JinyiRoleVO::getCode).collect(Collectors.toList());
        }
        return result;
    }

}

gateway 项目启动类

import com.jinyi.up.feignclient.UserProvideFeignClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
//@FeignClinet 和 @EnableFeignClients 不是同一个包。指定basePackages包扫描路径,指定basePackageClasses扫描类
@EnableFeignClients(basePackageClasses = {UserProvideFeignClient.class})
public class JinyiGateWayApplication {

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

yml配置文件bootstrap.yml 和 application-dev.yml
bootstrap.yml 如下

server:
  port: 8070

spring:
  application:
    name: jinyi-gateway
  main:
    allow-bean-definition-overriding: true
  profiles:
    active: dev
  cloud:
    nacos:
      # 注册中心
      discovery:
        server-addr: 127.0.0.1:8848
      # 配置中心
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
        group: GATEWAY_GROUP   # 配置中心  配置中心是空的
#        shared-configs[0]:
#          data-id: jinyi-common.yaml
#          group: COMMON_GROUP
#          refresh: true
    #gateway的配置
    gateway:
#      discovery:
#        locator:
#          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
#          lower-case-service-id: true
      #路由规则
      routes:
        - id: jinyi-user-provider # 路由的id,没有规定规则但要求唯一,建议配合服务名
          uri: lb://jinyi-user-provider #uri: lb://路由项目的spring.application.name
          #断言 用于路由规则的匹配 路径相匹配的进行路由
          predicates:
            - Path=/user-api/**  #用户路由
          filters:
            - StripPrefix=1  #去掉路由url中的前缀 /jinyi-user
            # 关键在下面一句,值为true则开启认证,false则不开启
            # 这种配置方式和spring cloud gateway内置的GatewayFilterFactory一致
          #  - Authorize=false #自定义的过滤工厂
logging:
  level:
    spring.: DEBUG


# Sa-Token配置
sa-token:
  # token名称 (同时也是cookie名称)
  token-name: token
  # token有效期,单位秒,默认30天, -1代表永不过期
  timeout: 2592000
  # token临时有效期 (指定时间内无操作就视为token过期),单位秒
  activity-timeout: -1
  # 是否允许同一账号并发登录 (为false时新登录挤掉旧登录)
  is-concurrent: true
  # 在多人登录同一账号时,是否共用一个token (为false时每次登录新建一个token)
  is-share: false
  # token风格
  token-style: uuid
  # 是否输出操作日志
  is-log: false
  # 是否从cookie中读取token
  is-read-cookie: false
  # 是否从head中读取token
  is-read-header: true
  # token前缀
#  token-prefix: Bearer

application-dev.yml如下

spring:
  redis:
    # Redis数据库索引(默认为0)
    database: 1
    # Redis服务器地址
    host: 127.0.0.1
    # Redis服务器连接端口
    port: 6379
    # Redis服务器连接密码(默认为空)
    password: 
    # 连接超时时间
    timeout: 10s
    lettuce:
      pool:
        # 连接池最大连接数
        max-active: 200
        # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: 3000ms
        # 连接池中的最大空闲连接
        max-idle: 10
        # 连接池中的最小空闲连接
        min-idle: 0

3.2jinyi-user-service服务
3.2.1 jinyi-user-api项目
pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>

<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>
        <artifactId>jinyi-user-service</artifactId>
        <groupId>com.jinyi.up</groupId>
        <version>1.0.0</version>
    </parent>

    <groupId>com.jinyi.up</groupId>
    <artifactId>jinyi-user-api</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <name>jinyi-user-api</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
</project>

dto 和 vo目录下的类分别是

import io.swagger.annotations.ApiModel;
import lombok.Data;

@Data
@ApiModel(value = "用户账号登录")
public class UserAccountLoginDTO {

    private String account;

    private String password;
}

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("用户角色VO")
public class JinyiRoleVO {

    @ApiModelProperty("主键id")
    private Long id;

    @ApiModelProperty("角色名称")
    private String name;

    @ApiModelProperty("角色编码")
    private String code;

    @ApiModelProperty("角色状态:1-正常;0-停用")
    private Boolean status;
}

jinyi-user-client项目:
pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<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">
    <parent>
        <artifactId>jinyi-user-service</artifactId>
        <groupId>com.jinyi.up</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>jinyi-user-client</artifactId>

    <name>jinyi-user-client</name>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <jinyi-up.version>1.0.0</jinyi-up.version>
    </properties>
    <dependencies>
        <!--引入base common-->
        <dependency>
            <groupId>com.jinyi.up</groupId>
            <artifactId>jinyi-common-base</artifactId>
            <version>${jinyi-up.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <!--            <optional>true</optional>-->
        </dependency>
        <!-- openfeign依赖 1. http客户端选择okhttp 2. loadbalancer替换ribbon -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
        </dependency>

        <dependency>
            <groupId>com.jinyi.up</groupId>
            <artifactId>jinyi-user-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.jinyi.up</groupId>
            <artifactId>jinyi-user-api</artifactId>
            <version>1.0.0</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>

</project>

核心feign类

import com.jinyi.up.common.base.result.R;
import com.jinyi.up.feignclient.fallback.UserProvideFeignFallback;
import com.jinyi.up.user.dto.UserAccountLoginDTO;
import com.jinyi.up.user.vo.JinyiRoleVO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.List;

/**
 * @FeignClient注解 value 指定的要代理的服务的spring:application:name配置信息
 * path 值的被代理的服务的统一路径
 */
@FeignClient(value = "jinyi-user-provider", path = "/jinyiUser",
        fallback = UserProvideFeignFallback.class) //实现UserProvideFeign服务降级
//        fallbackFactory = UserProvideFeignFallbackFactory.class)
public interface UserProvideFeignClient {

    @PostMapping("/accountLogin")
    R phoneLogin(@RequestBody UserAccountLoginDTO userPhoneLoginDTO);

    @GetMapping("/getUserRoleByUserId/{userId}")
    R<List<JinyiRoleVO>> getUserRoleByUserId(@PathVariable("userId") Long userId);
    
    @PostMapping("/userLogout")
    R userLogout();
}

jinyi-user-provider项目
pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<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>
        <artifactId>jinyi-user-service</artifactId>
        <groupId>com.jinyi.up</groupId>
        <version>1.0.0</version>
    </parent>
    <groupId>com.jinyi.up</groupId>
    <artifactId>jinyi-user-provider</artifactId>
    <version>1.0.0</version>

    <name>jinyi-user-provider</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <jinyi-up.version>1.0.0</jinyi-up.version>
        <sa-token.version>1.34.0</sa-token.version>
    </properties>

    <dependencies>
        <!-- 配置读取 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
        <!-- Spring Cloud & Alibaba -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <!-- 注册中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <!-- 配置中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--common基础依赖-->
        <dependency>
            <groupId>com.jinyi.up</groupId>
            <artifactId>jinyi-common-redis</artifactId>
            <version>${jinyi-up.version}</version>
        </dependency>
        <dependency>
            <groupId>com.jinyi.up</groupId>
            <artifactId>jinyi-common-mybatis-plus</artifactId>
            <version>${jinyi-up.version}</version>
        </dependency>
        <dependency>
            <groupId>com.jinyi.up</groupId>
            <artifactId>jinyi-common-web</artifactId>
            <version>${jinyi-up.version}</version>
        </dependency>

        <!-- sa-token -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-spring-boot-starter</artifactId>
            <version>${sa-token.version}</version>
        </dependency>
        <!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-dao-redis-jackson</artifactId>
            <version>${sa-token.version}</version>
        </dependency>
        <!-- 提供Redis连接池 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <dependency>
            <groupId>com.jinyi.up</groupId>
            <artifactId>jinyi-user-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.jinyi.up</groupId>
            <artifactId>jinyi-user-api</artifactId>
            <version>1.0.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
                <plugin>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.7.1</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

启动类

import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
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 java.net.InetAddress;
import java.net.UnknownHostException;

@Slf4j
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan(value = "com.jinyi.up.user.mapper")
public class JinyiUserProviderApplication {

    public static void main(String[] args) throws UnknownHostException {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(JinyiUserProviderApplication.class, args);

        Environment env = applicationContext.getEnvironment();
        String ip = InetAddress.getLocalHost().getHostAddress();
        String port = env.getProperty("server.port");
//        String activePrn ofile = SpringContext.getActiveProfile();
        log.info("\n----------------------------------------------------------\n\t" +
                "Application is running! Access URLs:\n\t" +
                "Doc: \t\thttp://" + ip + ":" + port + "/doc.html\n\t" +
                "Swagger: \thttp://" + ip + ":" + port + "/swagger-ui/\n\t" +
                "----------------------------------------------------------");
    }
}

yml配置文件bootstrap.yml 和 application-dev.yml
bootstrap.yml 如下

server:
  port: 8060
  
spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
  application:
    name: jinyi-user-provider
  main:
    allow-bean-definition-overriding: true
  profiles:
    active: dev
  cloud:
    nacos:
      # 注册中心
      discovery:
        server-addr: 1127.0.0.1:8848
      # 配置中心
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml  
        group: USER_GROUP 

#        shared-configs[0]:
#          data-id: jinyi-common.yaml
#          group: COMMON_GROUP
#          refresh: true

logging:
  level:
    spring.: DEBUG


# Sa-Token配置
sa-token:
  # token名称 (同时也是cookie名称)
  token-name: token
  # token有效期,单位秒,默认30天, -1代表永不过期
  timeout: 2592000
  # token临时有效期 (指定时间内无操作就视为token过期),单位秒
  activity-timeout: -1
  # 是否允许同一账号并发登录 (为false时新登录挤掉旧登录)
  is-concurrent: true
  # 在多人登录同一账号时,是否共用一个token (为false时每次登录新建一个token)
  is-share: false
  # token风格
  token-style: uuid
  # 是否输出操作日志
  is-log: false
  # 是否从cookie中读取token
  is-read-cookie: false
  # 是否从head中读取token
  is-read-header: true
  # token前缀
#  token-prefix: Bearer

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
spring:
  datasource:
    url: "jdbc:mysql://127.0.0.1:3306/jinyi_user_db?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true"
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
#    driver-class-name: com.mysql.jdbc.Driver
    hikari:
      minimum-idle: 16
      maximum-pool-size: 40
      connection-timeout: 3000
      idle-timeout: 50000
      validation-timeout: 60000
      max-lifetime: 86370
  redis:
    # Redis数据库索引(默认为0)
    database: 1
    # Redis服务器地址
    host: 127.0.0.1
    # Redis服务器连接端口
    port: 6379
    # Redis服务器连接密码(默认为空)
    password: 
    # 连接超时时间
    timeout: 10s
    lettuce:
      pool:
        # 连接池最大连接数
        max-active: 200
        # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: 3000ms
        # 连接池中的最大空闲连接
        max-idle: 10
        # 连接池中的最小空闲连接
        min-idle: 0

核心登录方法:

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.jinyi.up.common.base.result.R;
import com.jinyi.up.user.dto.UserAccountLoginDTO;
import com.jinyi.up.user.entity.JinyiRole;
import com.jinyi.up.user.entity.JinyiUser;
import com.jinyi.up.user.entity.JinyiUserRole;
import com.jinyi.up.user.service.IJinyiRoleService;
import com.jinyi.up.user.service.IJinyiUserRoleService;
import com.jinyi.up.user.service.IJinyiUserService;
import com.jinyi.up.user.vo.JinyiRoleVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Api(tags = "用户相关接口")
@RestController
@RequestMapping("/jinyiUser")
public class JinyiUserController {

    @Resource //用户服务
    private IJinyiUserService userService;
    @Resource //用户角色关联表服务
    private IJinyiUserRoleService userRoleService;
    @Resource //用户角色服务
    private IJinyiRoleService roleService;

    @ApiOperation(value = "用户账号登录", httpMethod = "POST")
    @PostMapping("/accountLogin")
    public R accountLogin(@RequestBody UserAccountLoginDTO userPhoneLoginDTO) {
        String account = userPhoneLoginDTO.getAccount();
        String password = userPhoneLoginDTO.getPassword();
        JinyiUser jinyiUser = userService.accountLogin(account, password);
        if (null != jinyiUser) {
        //密码校验通过后,直接调用登录
            StpUtil.login(jinyiUser.getId(), "PC");
            //登录成功后,返回相关的token信息
            return R.ok(StpUtil.getTokenInfo());
        }
        return R.failed("账号密码错误");
    }

    @ApiOperation(value = "查询用户对应的角色", httpMethod = "GET")
    @GetMapping("/getUserRoleByUserId/{userId}")
    public R<List<JinyiRoleVO>> getUserRoleByUserId(@PathVariable("userId") Long userId) {
        List<JinyiUserRole> userRoles = userRoleService.getByUserId(userId);
        if (CollectionUtils.isEmpty(userRoles)) {
            return R.ok();
        }
        Set<Integer> roleIds = userRoles.stream().map(JinyiUserRole::getRoleId).collect(Collectors.toSet());

        List<JinyiRole> roles = roleService.getByRoleIds(roleIds);
        if (CollectionUtils.isEmpty(roles)) {
            return R.ok();
        }
        List<JinyiRoleVO> jinyiRoleVOS = BeanUtil.copyToList(roles, JinyiRoleVO.class);
        return R.ok(jinyiRoleVOS);
    }

    @ApiOperation(value = "退出登录", httpMethod = "POST")
    @PostMapping("/userLogout")
    public R userLogout() {
        // 当前会话注销登录
        StpUtil.logout();
        return R.ok();
    }
}

最后测试

1.通过网关转发的登录
http://localhost:8070/user-api/jinyiUser/accountLogin
satoken+ gateway网关统一鉴权 初版
2.网关转发的其他需要登录带token的访问
satoken+ gateway网关统一鉴权 初版
satoken+ gateway网关统一鉴权 初版文章来源地址https://www.toymoban.com/news/detail-419176.html

到了这里,关于satoken+ gateway网关统一鉴权 初版的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Springcloud gateway网关+认证服务+token方式,入口层认证统一微服务鉴权【设计实践】

    目录 背景 实现 gateway maven配置 yml配置 页面登录拦截配置类 白名单配置 token工具类 登录配置类 全局过滤器类 项目启动类 分布式项目的单点登录分为认证服务(单点登录服务端)和业务服务(单点登录客户端)两个角色, 当访问业务服务时,认证服务客户端SDK校验一下是否

    2024年02月15日
    浏览(49)
  • SpringCloud网关Gateway认证鉴权【SpringCloud系列7】

    SpringCloud 大型系列课程正在制作中,欢迎大家关注与提意见。 程序员每天的CV 与 板砖,也要知其所以然,本系列课程可以帮助初学者学习 SpringBooot 项目开发 与 SpringCloud 微服务系列项目开发 本文章是系列文章中的一篇 1、SpringCloud 项目基础工程搭建 【SpringCloud系列1】 2、S

    2024年02月09日
    浏览(49)
  • SpringCloud搭建微服务之Gateway+Jwt实现统一鉴权

    在微服务项目中,需要对整个微服务系统进行权限校验,通常有两种方案,其一是每个微服务各自鉴权,其二是在网关统一鉴权,第二种方案只需要一次鉴权就行,避免了每个微服务重复鉴权的麻烦,本文以网关统一鉴权为例介绍如何搭建微服务鉴权项目。 本文案例中共有四

    2024年02月13日
    浏览(51)
  • Spring Cloud Gateway + Oauth2 实现统一认证和鉴权!

    micro-oauth2-gateway:网关服务,负责请求转发和鉴权功能,整合Spring Security+Oauth2; micro-oauth2-auth:Oauth2认证服务,负责对登录用户进行认证,整合Spring Security+Oauth2; micro-oauth2-api:受保护的API服务,用户鉴权通过后可以访问该服务,不整合Spring Security+Oauth2。 我们首先来搭建认

    2024年01月16日
    浏览(62)
  • 微服务-统一网关Gateway

    对用户请求做身份认证、权限校验 将用户请求路由到微服务,并实现负载均衡 对用户请求做限流 创建新module,命名为Gateway,引入依赖(1.SpringCloudGateway依赖;2.Eureka客户端依赖或者nacos的服务发现依赖)。在本案例中使用的是Eureka。 配置Application.yml的网关服务 路由id:路由

    2024年02月08日
    浏览(43)
  • 【微服务】八. 统一网关gateway

    网关功能: 身份认证和权限校验 服务路由、负载均衡 请求限流 网关的技术实现 在SpringCloud中网关的实现包括两种: gateway zuul Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。 网关的作用 对

    2024年02月07日
    浏览(50)
  • SpringCloud学习(七)——统一网关Gateway

    到现在,我们可以使用Nacos对不同的微服务进行注册并管理配置文件,也可以使用 Feign 对不同的微服务进行访问,但是,这种访问是任何人都可以访问的,这是不行的,访问之间应该有某种权限的控制,而且,如果所有允许的访问都可以进入,那么如果有一个时间访问量太过

    2024年02月06日
    浏览(31)
  • 微服务中间件--统一网关Gateway

    网关功能: 身份认证和权限校验 服务路由、负载均衡 请求限流 网关的技术实现 在SpringCloud中网关的实现包括两种: gateway zuul Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。 搭建网关服务

    2024年02月11日
    浏览(41)
  • SpringCloud微服务 【实用篇】| 统一网关Gateway

    目录 一:统一网关Gateway 1. 为什么需要网关 2. gateway快速入门 3. 断言工厂 4. 过滤器工厂 5. 全局过滤器 6. 跨域问题 前面我们已经学习了注册中心Eureka、Nacos和配置管理中心Nacos;但是此时存在很多安全的问题,服务器摆在那里谁都可以进行访问! 网关功能: ① 身份认证和权

    2024年02月04日
    浏览(43)
  • unity webgl导包问题 感谢大佬们

    问题1:Internal build system error. Backend exited with code 2. STDOUT: Finished compiling graph: 397 nodes, 1525 flattened edges (1521 ToBuild, 2 ToUse), maximum node priority 304 问题2:BuildFailedException: Incremental Player build failed! 问题3:Build completed with a result of \\\'Failed\\\' in 95 seconds (95449 ms) 问题4:UnityEditor.BuildPlayerW

    2024年02月12日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包