1. 内容说明

本文旨在使用开源轻量级 Java 权限认证框架sa-token+springcloud-gateway实现微服务在网关处统一鉴权。sa-token参考地址:https://sa-token.cc/doc.html#/ 项目按照业务分为三个板块,如图:

api(也就是微服务中各种api接口,不涉及任何权限相关代码,只提供服务)auth(认证中心,实现登陆逻辑)gateway(网关,实现转发等,主要是统一鉴权)

2. 项目实现

首先在idea创建一个项目mirco,然后在项目下依次创建三个module,这就不展开说了。接下来各模块填充内容。

2.1. auth模块

2.1.1. pom.xml依赖

主要是web、satoken、satoken整合redis:

org.springframework.boot

spring-boot-starter-web

2.3.5.RELEASE

cn.dev33

sa-token-spring-boot-starter

1.34.0

cn.dev33

sa-token-dao-redis-jackson

1.34.0

org.apache.commons

commons-pool2

2.1.2. controller类

提供登陆接口,实现登陆并返回登陆成功的token给前端:

import cn.dev33.satoken.stp.SaTokenInfo;

import cn.dev33.satoken.stp.StpUtil;

import cn.dev33.satoken.util.SaResult;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

public class AuthController {

@GetMapping("/auth/doLogin")

public SaResult doLogin(String username, String password) {

// 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对

if ("admin".equals(username) && "123456".equals(password)) {

StpUtil.login(10001);

} else if ("super".equals(username) && "123456".equals(password)) {

StpUtil.login(10002);

}else {

return SaResult.error("登录失败");

}

// 第3步,返回给前端

SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

return SaResult.ok("登录成功").setData(tokenInfo);

}

}

2.1.3. 启动类

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class AuthApplication {

public static void main(String[] args) {

SpringApplication.run(AuthApplication.class, args);

}

}

2.1.4. application.yml配置文件

server:

port: 8082

spring:

# redis配置

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: -1ms

# 连接池中的最大空闲连接

max-idle: 10

# 连接池中的最小空闲连接

min-idle: 0

2.2. gateway模块

2.2.1. pom.xml依赖

主要是gateway、satoken、satoken整合redis:

org.springframework.cloud

spring-cloud-starter-gateway

2.2.10.RELEASE

org.apache.httpcomponents

httpclient

4.5.13

cn.dev33

sa-token-reactor-spring-boot-starter

1.34.0

cn.dev33

sa-token-dao-redis-jackson

1.34.0

org.apache.commons

commons-pool2

2.2.2. 全局过滤器

主要是配置路由进行拦截鉴权,这里是整个鉴权的核心,具体的路由配置规则参考sa-token官网:

import cn.dev33.satoken.reactor.filter.SaReactorFilter;

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;

/**

* [Sa-Token 权限认证] 配置类

*/

@Configuration

public class SaTokenConfigure {

// 注册 Sa-Token全局过滤器

@Bean

public SaReactorFilter getSaReactorFilter() {

return new SaReactorFilter()

// 拦截地址

.addInclude("/**") /* 拦截全部path */

// 开放地址

.addExclude("/favicon.ico")

// 鉴权方法:每次访问进入

.setAuth(obj -> {

// 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录

SaRouter.match("/**", "/auth/doLogin", r -> StpUtil.checkLogin());

// 权限认证 -- 不同模块, 校验不同权限

SaRouter.match("/api/test1", r -> StpUtil.checkPermission("api.test1"));

SaRouter.match("/api/test2", r -> StpUtil.checkPermission("api.test2"));

SaRouter.match("/api/test3", r -> StpUtil.checkRoleOr("admin", "super"));

// 更多匹配 ... */

})

// 异常处理方法:每次setAuth函数出现异常时进入

.setError(e -> {

return SaResult.error(e.getMessage());

})

;

}

}

2.2.3. 自定义权限接口

主要是定义用户拥有的权限和角色,我这里直接写死的,实际项目中通常应该是auth认证模块登陆后从数据库查出用户的角色权限缓存到redis,然后这里再从redis取出来。

import cn.dev33.satoken.stp.StpInterface;

import org.springframework.stereotype.Component;

import java.util.ArrayList;

import java.util.List;

/**

* 自定义权限验证接口扩展,在需要鉴权时自动调用

*/

@Component

public class StpInterfaceImpl implements StpInterface {

/**

* 返回一个账号所拥有的权限码集合

*/

@Override

public List getPermissionList(Object loginId, String loginType) {

// 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限

List list = new ArrayList<>();

if (Integer.parseInt(loginId.toString()) == 10001) {

list.add("api.test1");

} else if (Integer.parseInt(loginId.toString()) == 10002) {

list.add("api.test2");

}

return list;

}

/**

* 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)

*/

@Override

public List getRoleList(Object loginId, String loginType) {

// 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色

List list = new ArrayList<>();

if (Integer.parseInt(loginId.toString()) == 10001) {

list.add("admin");

} else if (Integer.parseInt(loginId.toString()) == 10002) {

list.add("super");

}

return list;

}

}

2.2.4. 启动类

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class GatewayApplication {

public static void main(String[] args) {

SpringApplication.run(GatewayApplication.class, args);

}

}

2.2.5. application.yml配置文件

server:

port: 8083

spring:

application:

name: gateway

cloud:

gateway:

discovery:

locator:

enabled: true

lower-case-service-id: true

routes:

- id: api

uri: http://127.0.0.1:8081

predicates:

- Path=/api/**

- id: auth

uri: http://127.0.0.1:8082

predicates:

- Path=/auth/**

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: -1ms

# 连接池中的最大空闲连接

max-idle: 10

# 连接池中的最小空闲连接

min-idle: 0

2.3. auth模块

2.3.1. pom.xml依赖

主要是web:

org.springframework.boot

spring-boot-starter-web

2.3.2. controller类

提供一些接口,用来验证satoken权限:

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

public class TestController {

@GetMapping("/api/test1")

public String test1() {

return "访问成功--只有《api.test1》权限的才能访问";

}

@GetMapping("/api/test2")

public String test2() {

return "访问成功--只有《api.test2》权限的才能访问";

}

@GetMapping("/api/test3")

public String test3() {

return "访问成功--拥有《admin或者super角色》可以访问";

}

@GetMapping("/api/test4")

public String test4() {

return "访问成功--无需权限,登陆即可访问";

}

}

2.3.3. 启动类

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class ApiApplication {

public static void main(String[] args) {

SpringApplication.run(ApiApplication.class, args);

}

}

2.3.4. application.yml配置文件

server:

port: 8081

3. 项目测试

首先通过网关登陆:http://localhost:8083/auth/doLogin?username=admin&password=123456 如图正确的账户密码登陆成功返回token,这里登陆的admin用户。 不带token访问,访问失败:http://localhost:8083/api/test1 携带token访问,访问成功:http://localhost:8083/api/test1 访问无权限的接口失败:http://localhost:8083/api/test2

访问有角色权限的接口成功:http://localhost:8083/api/test3

4. 项目总结

至此,我们完成了gateway处统一使用sa-token鉴权。以上只是最基础的网关统一鉴权的使用,更深层的比如内外网隔离等请自行参考sa-token官网。个人觉得sa-token相当牛逼,十分容易上手,不管你是单体、前后端分离还是微服务项目,都能轻松集成。相比于springsecurity学习成本降低很多。 另外本博客涉及的代码已全部包含在文章里了,就不另外贴了。

精彩文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。