当前位置: 代码网 > it编程>编程语言>Java > SpringCloud整合GateWay+Sa-Token做登录验证(干货)

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

2024年08月02日 Java 我要评论
等一系列权限相关问题,在这里我就不详细介绍了,想要了解的同学可以去查看官方文档 https://sa-token.cc/doc.html。

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

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com