纠错:
在上一部分里我完成了微服务框架的初步实现,但是先说一下之前有一个错误,就是依赖部分
上次的学习中我在总的父模块下引入了spring-boot-dependencies(版本控制)我以为在子模块下就不需要再引用了,虽然没有报错,但是还是需要在starter模块中再引用一次
修改如下:在starter模块下
添加spring-boot-dependencies
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
下面我们来开始编写鉴权实现
首先我们要清楚我们需要实现的流程
用户访问时需要通过网关层,网关会进行用户鉴权,由nacos分配到指定服务
这里为什么auth服务要在其他服务之上呢,因为用户需要在auth服务中进行登录,获取其专属的token,在请求头中带着token,才能访问其他的服务。
Nacos:
什么是Nacos?目前我对nacos的理解是,管理与动态分配微服务
后面我说的都是自己的理解,可能不是那么准确,请大家自行百度哈哈哈。
黑马SpringCloud微服务全通关,一套精通springcloud全技术栈Eureka、 Nacos、OpenFeign、网关Gateway、 Spring_哔哩哔哩_bilibili
(不是打广告哈哈哈,这个讲的简洁不墨迹,读文章难受的建议食用)
nacos是一个注册中心 ,我们在创建一个微服务时,需要将微服务注册到nacos上。
我们可以把nacos看成一个map表,键是微服务的名称,值是微服务本身,我们可以通过nacos找到想要的微服务。
比如说网关鉴权,微服务之间的调用,都需要nacos来提供微服务。
nacos搭建
nacos我在自己的服务器上使用的是docker安装,但是这次作为演示,就在windows本机上安装了
链接:https://pan.baidu.com/s/1V4OUO46LZXRym2yzG4DcWQ?pwd=1111
提取码:1111
下载好后,进入bin目录,在该目录下打开cmd终端,输入:
startup.cmd -m standalone
启动成功后我们可以看到一个地址,复制粘贴到浏览器,账号密码都是nacos,就可以成功进入了
nacos配置
这次我们需要新建两个微服务,一个是auth微服务,一个是gateway微服务
auth服务骨干如下,和之前是一样的,不知道的可以回去看一下,就是改了一个名字
还有网关服务:movie-gateway
骨干如下:不需要分层
下面我介绍一个工具,是阿里的脚手架。地址:https://start.aliyun.com/
这个工具可以帮我们整理spring could和springboot的一些版本冲突
我的spring boot版本是2.4.2 ,选择对应的版本,在这里搜索需要引入的依赖,点击下方的浏览代码
我们就可以看到对应的版本号和需要引入的依赖了,下面我们开始正式的引入
movie-catalogue服务:
总模块:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.2</version>
<type>pom</type>
<scope>compile</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.4.2</spring-boot.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
<spring-cloud.version>2020.0.6</spring-cloud.version>
</properties>
starter模块:
<dependencies>
<dependency>
<groupId>com.yizhiliulianta</groupId>
<artifactId>movie-catalogue-application-controller</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<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>
<exclusions>
<exclusion>
<artifactId>snakeyaml</artifactId>
<groupId>org.yaml</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.0.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
movie-auth服务:
总模块:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.2</version>
<type>pom</type>
<scope>compile</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.4.2</spring-boot.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
<spring-cloud.version>2020.0.6</spring-cloud.version>
</properties>
starter模块:
<dependencies>
<dependency>
<groupId>com.yizhiliulianta</groupId>
<artifactId>movie-auth-application-controller</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<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>
<exclusions>
<exclusion>
<artifactId>snakeyaml</artifactId>
<groupId>org.yaml</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.0.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
其他的模块我就不粘了,直接将matalogue引入的依赖,粘贴到对应的auth模块依赖下就行了
而movie-gateway的依赖在后面展示
nacos配置文件:
movie-auth服务:
下面我们在movie-auth服务下的starter模块的配置目录下新建bootstap.xml文件
spring:
application:
name: movie-auth
cloud:
nacos:
discovery:
server-addr: 192.168.38.189:5000
enabled: true
application.name:注册到nacos上的服务名
cloud.nacos.discovery.server-addr:nacos的地址(就是开始启动nacos给你的地址和端口)
cloud.nacos.discovery.enabled:启用nacos的服务发现功能
movie-catalogue服务:
spring:
application:
name: movie-catalogue
cloud:
nacos:
discovery:
server-addr: 192.168.38.189:5000
enabled: true
movie-gateway服务:
spring:
application:
name: movie-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.38.189:5000
enabled: true
启动所有服务,启动类我就不展示了
打开刚刚的网址,发现所有服务成功注册!
Sa-Token:
Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证、权限认证、Session会话、单点登录、OAuth2.0、微服务网关鉴权 等一系列权限相关问题
我不再去详细介绍了,大家知道这是一款很好用的鉴权框架,而且文档非常详细,大家可以之间去食用。
官方地址:Sa-Token
本次是集成redis,redis我就不带大家去安装了,下面是安装包,无脑下一步就好,大家可以去搜一下怎么安装,很简单,我这里安装过了,不去展示了
Redis:
链接:https://pan.baidu.com/s/1njAjHRm8bUzMOCqo3z6whg?pwd=1111
提取码:1111
找到刚刚安装的文件夹,然后点击redis-cli.exe
还是依赖...哈哈哈。本次我们要和redis集成,大家可以照抄我的依赖
movie-gateway服务:
总依赖:
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.4.2</spring-boot.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
<spring-cloud.version>2020.0.6</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<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>
<exclusions>
<exclusion>
<artifactId>snakeyaml</artifactId>
<groupId>org.yaml</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<!-- Sa-Token 权限认证(Reactor响应式集成), 在线文档:https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-reactor-spring-boot-starter</artifactId>
<version>1.38.0</version>
</dependency>
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>1.38.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
</dependencies>
配置文件:
下面是配置文件的编写,在application.yml文件下添加
server:
port: 2000
spring:
cloud:
gateway:
routes:
- id: movie-catalogue
uri: lb://movie-catalogue
predicates:
- Path=/catalogue/**
filters:
- StripPrefix=1
- id: movie-auth
uri: lb://movie-auth
predicates:
- Path=/auth/**
filters:
- StripPrefix=1
# redis配置
redis:
# Redis数据库索引(默认为0)
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池最大连接数
max-active: 200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# 连接池中的最大空闲连接
max-idle: 10
# 连接池中的最小空闲连接
min-idle: 0
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: satoken
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
timeout: 2592000
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
active-timeout: -1
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
is-share: true
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
token-style: random-32
# 是否输出操作日志
is-log: true
movie-auth服务:
controller模块依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.2</version>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.yizhiliulianta</groupId>
<artifactId>movie-auth-domain</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Sa-Token 权限认证 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.38.0</version>
</dependency>
</dependencies>
common模块依赖:
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<!-- 数据映射-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.2.Final</version>
</dependency>
<!-- 日志-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.4.2</version>
</dependency>
<!-- json解析工具-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
<!-- json工具-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
<scope>compile</scope>
</dependency>
<!-- 集合,对象,字符串等工具-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
<!-- 断言检查-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>1.37.0</version>
</dependency>
<!-- 提供Redis连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
下面是配置文件的编写,在application.yml文件下添加
server:
port: 1001
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
spring:
datasource:
username: root
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/movieweb?useUnicode=true&serverTimezone=Asia/Shanghai&useSSL=true&characterEncoding=utf-8
password: 123456
# redis配置
redis:
# Redis数据库索引(默认为0)
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池最大连接数
max-active: 200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# 连接池中的最大空闲连接
max-idle: 10
# 连接池中的最小空闲连接
min-idle: 0
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: satoken
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
timeout: 2592000
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
active-timeout: -1
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
is-share: true
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
token-style: random-32
# 是否输出操作日志
is-log: true
现在所有的基础环境和依赖,我们都配置完成了
表建立:
我们开始鉴权模块的编写了,首先我们需要三张表,分别是,用户,权限,用户和权限的映射
用户表:(用户名和密码)
权限表:(权限的名字,权限的状态,权限的键)
映射表:(用户的id和权限id的映射)
大家看着自己建表吧,太简单了。
代码实现:
下面开始代码的基础编写,还是和电影一样的流程,dto转bo,domain层做逻辑,我偷懒了,只做了一个新增用户,我不去粘代码了,我就粘贴一下domain层的主要逻辑了,我相信大家是可以写出来的哈哈哈,参考上一篇
domain层:
package com.yizhiliulianta.auth.domain.service.impl;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import com.google.gson.Gson;
import com.yizhiliulianta.auth.domain.bo.AuthUserBO;
import com.yizhiliulianta.auth.domain.constants.AuthConstant;
import com.yizhiliulianta.auth.domain.converter.AuthUserBOConverter;
import com.yizhiliulianta.auth.domain.redis.RedisUtil;
import com.yizhiliulianta.auth.domain.service.AuthUserDomainService;
import com.yizhiliulianta.auth.infra.entity.AuthPermission;
import com.yizhiliulianta.auth.infra.entity.AuthUser;
import com.yizhiliulianta.auth.infra.entity.AuthUserPermission;
import com.yizhiliulianta.auth.infra.service.AuthPermissionService;
import com.yizhiliulianta.auth.infra.service.AuthUserPermissionService;
import com.yizhiliulianta.auth.infra.service.AuthUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
@Service
@Slf4j
public class AuthUserDomainServiceImpl implements AuthUserDomainService {
@Resource
private AuthUserService authUserService;
@Resource
private AuthPermissionService authPermissionService;
@Resource
private AuthUserPermissionService authUserPermissionService;
@Resource
private RedisUtil redisUtil;
private final String salt = "yizhiliulianta";
private final String userPermissionPrefix = "user.permission";
@Override
public Boolean register(AuthUserBO authUserBO) {
AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBOToAuth(authUserBO);
if (StringUtils.isNotBlank(authUser.getPassword())){
authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(),salt));
}
//插入用户
AuthUser user = authUserService.insert(authUser);
AuthPermission authPermission = new AuthPermission();
//获取对应权限信息
authPermission.setPermissionKey(AuthConstant.PERMISSION_KEY);
AuthPermission permissionResult = authPermissionService.queryByCondition(authPermission);
//用户与权限做关联
Long userId = user.getId();
Long permissionResultId = permissionResult.getId();
AuthUserPermission authUserPermission = new AuthUserPermission();
authUserPermission.setUserId(userId);
authUserPermission.setPermissionId(permissionResultId);
authUserPermissionService.insert(authUserPermission);
//放入redis
String buildKey = redisUtil.buildKey(userPermissionPrefix, authUser.getUserName());
List<AuthPermission> authPermissionList = new LinkedList<>();
authPermissionList.add(permissionResult);
redisUtil.set(buildKey,new Gson().toJson(authPermissionList));
return true;
}
@Override
public SaTokenInfo doLogin(String validCode) {
return null;
}
@Override
public AuthUserBO getUserInfo(AuthUserBO authUserBO) {
return null;
}
}
这里就是两张表分别进行插入,首先查询出插入的用户对象和需要绑定的权限,通过映射表的对象,来绑定一个映射对象,继续插入。权限可能是多个,所以我用了一个集合来保存权限,也是直接可以将权限丢入的。
movie-gateway代码实现:
下面我们开始movie-gateway的编写
首先我们需要编写一个权限认证配置器,代码如下:
权限认证配置器:
package com.yizhiliulianta.gateway.auth;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 权限认证的配置器
*/
@Configuration
public class SaTokenConfigure {
// 注册 Sa-Token全局过滤器
@Bean
public SaReactorFilter getSaReactorFilter() {
return new SaReactorFilter()
// 拦截地址
.addInclude("/**") /* 拦截全部path */
// 鉴权方法:每次访问进入
.setAuth(obj -> {
System.out.println("---- 前端访问path:" + SaHolder.getRequest().getRequestPath());
// 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
SaRouter.match("/**", "/auth/user/doLogin", r -> StpUtil.checkPermission("movie:select"));
});
}
}
这个配置器的作用是拦截所有路径,进行登录的校验,查看该用户是否具有对应权限,但是登录,不能拦截,所以排除了登录路径
权限认证接口实现:
package com.yizhiliulianta.gateway.auth;
import cn.dev33.satoken.stp.StpInterface;
import com.alibaba.nacos.api.utils.StringUtils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yizhiliulianta.gateway.entity.AuthPermission;
import com.yizhiliulianta.gateway.redis.RedisUtil;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 自定义权限验证接口扩展
*/
@Component
public class StpInterfaceImpl implements StpInterface {
@Resource
private RedisUtil redisUtil;
private final String userPermissionPrefix = "user.permission";
//获取权限
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
String authKey = redisUtil.buildKey(userPermissionPrefix, loginId.toString());
String authValue = redisUtil.get(authKey);
if (StringUtils.isBlank(authValue)){
return Collections.emptyList();
}
List<AuthPermission> permissionList = new Gson().fromJson(authValue, new TypeToken<List<AuthPermission>>(){
}.getType());
return permissionList.stream().map(AuthPermission::getPermissionKey).collect(Collectors.toList());
}
//获取角色
@Override
public List<String> getRoleList(Object loginId, String loginType) {
return null;
}
}
重写两个方法,因为本次演示一下satoken的使用,并没有添加角色role的实现,所以我只实现了获取权限的方法。首先拼接一个key,去redis中去取,得到的值就是我们刚刚放入的权限详细信息,我们将其转换成java对象,通过steam流获取它的key键,就是我们数据库中的permissionkey,也就是配置器中的验证数据。
验证操作:
下面我们在auth服务中,验证一下整体的流程,在controller添加两个验证方法,代码如下
// 会话登录接口
@RequestMapping("doLogin")
public SaResult doLogin(String name, String pwd) {
// 第一步:比对前端提交的账号名称、密码
if("zhang".equals(name) && "123456".equals(pwd)) {
// 第二步:根据账号id,进行登录
StpUtil.login("一支榴莲挞");
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
return SaResult.data(tokenInfo);
}
return SaResult.error("登录失败");
}
// 查询登录状态 ---- http://localhost:8081/acc/isLogin
@RequestMapping("isLogin")
public SaResult isLogin() {
return SaResult.ok("是否登录:" + StpUtil.isLogin());
}
dologin方法中接收前端传来的参数来模拟传入的账号密码,如果一致则登录成功,利用satoken的login方法进行登录,这里的”你好“就是一个模拟,在后面我们会和微信登录对接,这里放的是真实的用户名,然后返回一个对应的token,而下面的方法就是验证刚刚的鉴权有没用成功。
下面请出我们的apipost
首先第一步,我们要实现用户的注册
添加成功!
下面我们开始来测试网关
很完美,成功了,我们可以看到token和loginid,我们将token复制,添加到请求头,开始用islogin接口进行测试
我们观察到成功了,证明我们的网关和auth打通了,但是大家可能会有疑问,鉴权真的打通了吗
那我们再次操作一下,首先是我们不带token
可以看到无权限,失败了,因为网关拦截住了,证明token是没有问题的,那么下面就是鉴权
我们在配置器中修改一下权限规则,我这里随便修改一下,改成abc,我们重启服务试一下
没有通过网关,证明没有权限,与配置的规则不匹配,这下我们可以发现,网关和satoken成功配置,下一次我们要实现的是微信公众号与登录进行打通。
总结:
让我们回顾一下这次的任务流程,首先是编写了用户与权限的增删改查(只完成了增哈哈哈偷懒了),然后将三个服务注册到nacos中,引入satoken鉴权框架,并于redis集成,通过缓存来获取用户权限。
用户登录实现的过程:注册----》登录-----》获取token----》网关拦截,通过token在redis中获取权限信息来判断是否符合规则
附录:
代码不是很全,因为类真的很多,如果大家想要代码的话可以私信我,下次完成微信打通,我将代码放到gitee上,方便大家拉取