SpringCloud整合GateWay+Sa-Token做登录验证(干货)

SpringCloud整合GateWay+Sa-Token做登录验证(干货)

一、什么是Sa-Token?

Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证权限认证单点登录OAuth2.0分布式Session会话微服务网关鉴权 等一系列权限相关问题,在这里我就不详细介绍了,想要了解的同学可以去查看官方文档 https://sa-token.cc/doc.html

二、关于GateWay

GateWay网关是我们服务的守门神,是统一入口处

核心功能特性:

1.请求路由:通过特定的规则将请求转发到对应的微服务

2.权限控制:进入不同微服务之前都要进行一个验证

3.限流:当请求流量过高时就要限流

在这里插入图片描述

在这里插入图片描述

三、具体步骤

项目结构

在这里插入图片描述

1、配置网关服务

在gateway模块引入依赖
<?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>data_factory_cloud</artifactId>
        <groupId>com.wjk</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>data_factory_cloud_gateway</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <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>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- httpClient依赖,缺少此依赖api网关转发请求时可能发生503错误 -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>
        <!--redis坐标       -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.9.0</version> <!-- 请使用最新的版本号 -->
        </dependency>
    </dependencies>

</project>
在application.yml文件里面进行配置
server:
  port: 10010
spring:
  application:
    name: gateway

  cloud:
    nacos:
      server-addr: localhost:8848
    gateway:
      routes:
        - id: source_database
          uri: lb://source_database #负载均衡
          predicates: #路由断言,判断请求是否符合规则
            - Path=/sourceDatabase/** #路径断言,判断路径是否是以/user开头,如果是符合
#          filters: #过滤器
#            - AddRequestHeader=Truth,Itcast is freaking aowsome!
        - id: code
          uri: lb://code
          predicates:
            - Path=/code/**
        - id: user
          uri: lb://user
          predicates:
            - Path=/user/**
        - id: data_asset
          uri: lb://data_asset
          predicates:
            - Path=/dataAsset/**
        - id: data_standard
          uri: lb://data_standard
          predicates:
            - Path=/order/**
        - id: sourceApi
          uri: lb://data_standard
          predicates:
            - Path=/sourceApi/**
  redis:
    host: 192.168.246.133
    port: 6379
    timeout: 10s
    #    password: 123456
    #    database: 0
    lettuce:
      pool:
        max-active: 10
        max-wait: -1
        max-idle: 16
        min-idle: 8
# Sa-Token配置
sa-token:
  # token名称 (同时也是cookie名称)
  token-name: sa-token-authorization
  # token有效期,单位s 默认30天, -1代表永不过期
  timeout: 2592000
  # token风格
  token-style: random-32
  # 是否尝试从 header 里读取 Token
  is-read-head: true
  # 是否开启自动续签
  auto-renew: true
  # 临时有效期,单位s,例如将其配置为 1800 (30分钟),代表用户如果30分钟无操作,则此Token会立即过期
  activity-timeout: -1
  # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时同端互斥)
  is-concurrent: true
  # 配置 Sa-Token 单独使用的 Redis 连接
  alone-redis:
    # Redis数据库索引(默认为0)
    database: 0
    # Redis服务器地址
    host: 192.168.246.133
    # Redis服务器连接端口
    port: 6379
    # Redis服务器连接密码(默认为空)
    #    password:
    # 连接超时时间
    timeout: 10s
新建类SaTokenConfigure,实现网关拦截
package com.wjk.config;

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;

/**
 * @author YangBoss
 * @title: SaTokenConfigure
 * @projectName meta
 * @description: TODO
 * @date 2022/8/18 10:12
 */
@Configuration
public class SaTokenConfigure {
    // 注册 Sa-Token全局过滤器
    @Bean
    public SaReactorFilter getSaReactorFilter() {
        return new SaReactorFilter()
                // 拦截地址
                .addInclude("/**")
                // 开放地址
                .addExclude("/user/login")
                .addExclude("/user/sendEmail")
                .addExclude("/user/regist")
                // 鉴权方法:每次访问进入
                .setAuth(obj -> {
                    // 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
                    SaRouter.match("/**", "/user/login", r -> StpUtil.checkLogin());
                    SaRouter.match("/**", "/user/regist", r -> StpUtil.checkLogin());
                    SaRouter.match("/**", "/user/sendEmail", r -> StpUtil.checkLogin());
//                    // 角色认证 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证
//                    SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));
//                    // 权限认证 -- 不同模块, 校验不同权限
//                    SaRouter.match("/meta-system/**", r -> StpUtil.checkPermission("system-no"));
//                    SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
//                    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");
//                    return new ResultJsonUtil().fail(e.getMessage());
                    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();
                });

    }



}

2、配置用户服务

引入依赖
<?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>data_factory_cloud</artifactId>
        <groupId>com.wjk</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>data_factory_cloud_user</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.wjk</groupId>
            <artifactId>data_factory_cloud_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- sa-token权限认证框架 -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-spring-boot-starter</artifactId>
            <version>1.37.0</version>
        </dependency>
        <!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-redis-jackson</artifactId>
            <version>1.37.0</version>
        </dependency>
        <!-- Spring Boot Starter Mail -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
    </dependencies>

</project>

在yml文件里面配置

# Sa-Token配置
sa-token:
  # token名称 (同时也是cookie名称)
  token-name: sa-token-authorization
  # token有效期,单位s 默认30天, -1代表永不过期
  timeout: 3600
  # token风格
  token-style: random-32
  # 是否尝试从 header 里读取 Token
  is-read-head: true
  # 是否开启自动续签
  auto-renew: true
  # 临时有效期,单位s,例如将其配置为 1800 (30分钟),代表用户如果30分钟无操作,则此Token会立即过期
  activity-timeout: 1800
  # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时同端互斥)
  is-concurrent: true
  # 配置 Sa-Token 单独使用的 Redis 连接
  alone-redis:
    # Redis数据库索引(默认为0)
    database: 0
    # Redis服务器地址
    host: 192.168.246.133
    # Redis服务器连接端口
    port: 6379
    # Redis服务器连接密码(默认为空)
    #    password:
    # 连接超时时间
    timeout: 30s
编写登录接口

UserService

package com.wjk.service;

import cn.dev33.satoken.util.SaResult;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wjk.entity.User;
import com.wjk.result.R;
import com.wjk.VO.UserVo;

public interface UserService extends IService<User> {
    //发送验证码邮件给指定邮箱
    R sendMimeMail(String email);
    //随机生成6位数字验证码
    String randomCode();
    //用户注册,验证验证码并保存用户信息
    R registered(UserVo userVo);
    //登录
    SaResult login(String email, String password) throws Exception;
    //登出
    SaResult logout();
}

UserServiceImpl

@Override
public SaResult login(String email, String password) throws Exception {
    //根据用户名从数据库中查询
    User user = this.getOne(Wrappers.lambdaQuery(User.class).eq(User::getEmail,email));
    System.out.println(user);
    if(user == null){
        return SaResult.error("用户名不存在");
    }
    //对登录密码进行加密
    boolean result = Md5Util.passwordVerify(password, user.getPassword(), Md5Util.md5Key);
    if(result){
        //根据用户id登录,第1步,先登录上
        StpUtil.login(user.getId());
        // 第2步,获取 Token  相关参数
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        // 第3步,返回给前端
        return SaResult.data(tokenInfo);
    }
    return SaResult.error("密码错误");
}

User

package com.wjk.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@TableName("users")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    @TableField("username")
    private String username;
    @TableField("password")
    private String password;
    @TableField("email")
    private String email;
    @TableField("created_at")
    private Date createdAt;
}

UserVo

package com.wjk.VO;

import lombok.Data;

@Data
public class UserVo {
    private String username;
    private String password;
    private String email;
    //验证码
    private String code;
}

UserVoToUser

package com.wjk.VO;

import com.wjk.entity.User;

public class UserVoToUser {
    /**
     * 将表单中的对象转化为数据库中存储的用户对象,剔除表单中的验证码字段。
     *
     * @param userVo 表单中的对象
     * @return 数据库中存储的用户对象
     */
    public static User toUser(UserVo userVo) {
        // 创建一个数据库中存储的对象
        User user = new User();
        // 赋值
        user.setUsername(userVo.getUsername());
        user.setPassword(userVo.getPassword());
        user.setEmail(userVo.getEmail());
        // 返回转化后的对象
        return user;
    }
}

MD5加密

package com.wjk.utils;

import org.apache.commons.codec.digest.DigestUtils;

public class Md5Util {

    // 实现一个md5加解密

    public final static String md5Key = "lalalalall";

    /**
     *
     * @param strPwd 明文密码
     * @param
     * @return 密文
     * @throws Exception
     */
    //用于注册时对密码进行加密
    public static String md5(String strPwd,String Key) throws Exception{
        // 获取加密后的字符串
        String encodeStr = DigestUtils.md5Hex(strPwd + Key);//调用加密的算法
        return encodeStr;
    }

    /**
     * 用户登录,密码验证
     * @param pwdStr 明文字符串
     * @param oldPwd 密文字符串
     * @return
     */
    public static boolean passwordVerify(String pwdStr,String oldPwd,String key) throws Exception {
        //在该方法中,不需要在外面做密码加密,登录时获取到当前用户输入的密码,在方法里进行加密
        String md5Pwd= md5(pwdStr,key);
        if (md5Pwd.equalsIgnoreCase(oldPwd)){
            return true;
        }
        return false;
    }

}

controller

package com.wjk.controller;
import cn.dev33.satoken.util.SaResult;
import com.wjk.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@RequestMapping("/user")
public class LoginController {
    @Resource
    private UserService userService;

    @GetMapping("/login")
    public SaResult login(String email, String password) throws Exception {
        return userService.login(email,password);
    }
    @GetMapping("/logout")
    public SaResult logout(){
       return userService.logout();
    }
}
测试

发送验证码

在这里插入图片描述

根据验证码进行注册

在这里插入图片描述

登录

在这里插入图片描述

我这里的端口号10010对应的是gateway模块里的yml文件里面配置的端口号,这就是统一入口处,由它进行请求转发,肯定不止向登录模块请求转发,还会向别的端口进行,那么配置也跟上面一样,在gateway里面的yml文件里面要配置

gateway:
      routes:
        - id: source_database
          uri: lb://source_database
          predicates: #路由断言,判断请求是否符合规则
            - Path=/sourceDatabase/** #路径断言,判断路径是否是以/user开头,如果是符合
#          filters: #过滤器
#            - AddRequestHeader=Truth,Itcast is freaking aowsome!
        - id: code
          uri: lb://code
          predicates:
            - Path=/code/**
        - id: user
          uri: lb://user
          predicates:
            - Path=/user/**
        - id: data_asset
          uri: lb://data_asset
          predicates:
            - Path=/dataAsset/**
        - id: data_standard
          uri: lb://data_standard
          predicates:
            - Path=/order/**
        - id: sourceApi
          uri: lb://data_standard
          predicates:
            - Path=/sourceApi/**

该项目具体代码在gitee

https://gitee.com/wjk0321/data_factory_cloud

uri: lb://code
predicates:
- Path=/code/**
- id: user
uri: lb://user
predicates:
- Path=/user/**
- id: data_asset
uri: lb://data_asset
predicates:
- Path=/dataAsset/**
- id: data_standard
uri: lb://data_standard
predicates:
- Path=/order/**
- id: sourceApi
uri: lb://data_standard
predicates:
- Path=/sourceApi/**


该项目具体代码在gitee

https://gitee.com/wjk0321/data_factory_cloud

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringCloud是基于Spring框架的分布式系统开发框架,它提供了丰富的分布式系统解决方案。而Sa-Token是一个轻量级的Java权限认证与授权框架,提供了简单易用的权限控制功能。 在SpringCloud整合Sa-Token可以为我们的分布式系统提供更加安全可靠的权限认证与授权机制。具体步骤如下: 1. 在SpringCloud的微服务架构中,将Sa-Token配置为一个独立的授权认证中心,可以独立部署,也方便对其进行管理和维护。 2. 在每个微服务中引入Sa-Token的依赖,通过配置Sa-Token的相关属性,实现微服务的用户登录与认证。同时,可以使用Sa-Token提供的注解进行权限控制,例如@RequiresPermissions注解可以对接口或方法进行权限校验。 3. 在微服务之间进行访问时,可以通过Sa-TokenToken验证机制,对调用方进行身份认证。因此,每个微服务需要验证并解析Token,以确保请求方的合法性。 4. Sa-Token提供了灵活的权限授权机制,可以根据业务需求配置不同的角色和权限管理。在SpringCloud中,我们可以根据微服务的不同职能划分角色,为每个角色分配相应的权限。通过角色与权限的配置,实现对不同微服务接口的精确控制。 通过将Sa-Token整合SpringCloud中,我们可以实现整个系统的统一权限管理。无论是对用户的认证与授权,还是对接口的权限控制,都可以通过Sa-Token轻松实现。这不仅提高了系统的安全性,同时也简化了系统的开发与维护工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值