Я помню статью, которую я написал раньшеSpring Cloud Gateway + Oauth2 — идеальное решение для разрешений микросервисов, реализующее унифицированную аутентификацию и аутентификацию!, предоставляет решение для разрешения в Spring Cloud. На самом деле, я не мог воспроизвести его в начале интеграции. Я проверил данные и посмотрел исходный код и, наконец, преуспел. Недавно я попробовал решение для разрешения микросервисов, предоставляемое Sa-Token, и оно кажется очень элегантным в использовании. Я рекомендую его всем!
Адрес фактического центра электронной коммерции SpringBoot (50k+star):GitHub.com/macro-positive/…
Предварительное знание
Мы будем использовать Nacos в качестве центра регистрации, Gateway в качестве шлюза и использовать решение для разрешения микросервисов, предоставляемое Sa-Token.Это решение основано на предыдущем решении.Друзья, которые не знакомы с этими технологиями, могут прочитать следующую статью.
- Spring Cloud Gateway: новое поколение сервисов шлюза API
- Spring Cloud Alibaba: Nacos используется как центр регистрации и настройки
- Spring Cloud Gateway + Oauth2 — идеальное решение для разрешений микросервисов, реализующее унифицированную аутентификацию и аутентификацию!
- Руководство по использованию Sa-Token
Архитектура приложения
Это та же идея, что и в предыдущем решении: служба аутентификации отвечает за обработку входа в систему, шлюз отвечает за аутентификацию входа и аутентификацию полномочий, а другие службы API отвечают за обработку своей собственной бизнес-логики. Чтобы разделить сеансы Sa-Token между несколькими службами, все службы должны интегрировать Sa-Token и Redis.
- micro-sa-token-common: общий инструментарий, пользовательский класс, общий для других сервисов.
UserDTO
и общий класс возвращаемого результатаCommonResult
извлечено здесь. - micro-sa-token-gateway: служба шлюза, отвечающая за переадресацию запросов, аутентификацию входа и авторизацию.
- micro-sa-token-auth: служба аутентификации, включающая только один интерфейс входа в систему, который вызывает реализацию API Sa-Token.
- micro-sa-token-api: защищенный сервис API, пользователи могут получить доступ к сервису после прохождения аутентификации на шлюзе.
Реализация схемы
Затем внедрите следующий набор решений и поочередно создайте службы шлюза, службы проверки подлинности и службы API.
micro-sa-token-gateway
Давайте сначала создадим службу шлюза, которая будет отвечать за аутентификацию входа и аутентификацию разрешений всего микросервиса.
- В дополнение к общим зависимостям шлюза нам также необходимо
pom.xml
Добавьте следующие зависимости вmicro-sa-token-common
полагаться;
<dependencies>
<!-- Sa-Token 权限认证(Reactor响应式集成) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-reactor-spring-boot-starter</artifactId>
<version>1.24.0</version>
</dependency>
<!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.24.0</version>
</dependency>
<!-- 提供Redis连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- micro-sa-token通用依赖 -->
<dependency>
<groupId>com.macro.cloud</groupId>
<artifactId>micro-sa-token-common</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
- Далее модифицируем конфигурационный файл
application.yml
, добавьте конфигурацию Redis и конфигурацию Sa-Token, если вы читали предыдущуюРуководство по использованию Sa-TokenЕсли это так, вы в основном знаете роль этих конфигураций;
spring:
redis:
database: 0
port: 6379
host: localhost
password:
# Sa-Token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: Authorization
# token有效期,单位秒,-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-head: true
- Добавить класс конфигурации для Sa-Token
SaTokenConfig
, введите фильтр для аутентификации входа и аутентификации разрешений, вsetAuth
Добавьте правила маршрутизации в метод, вsetError
Добавьте в метод обработку обратного вызова при сбое аутентификации;
@Configuration
public class SaTokenConfig {
/**
* 注册Sa-Token全局过滤器
*/
@Bean
public SaReactorFilter getSaReactorFilter() {
return new SaReactorFilter()
// 拦截地址
.addInclude("/**")
// 开放地址
.addExclude("/favicon.ico")
// 鉴权方法:每次访问进入
.setAuth(r -> {
// 登录认证:除登录接口都需要认证
SaRouter.match("/**", "/auth/user/login", StpUtil::checkLogin);
// 权限认证:不同接口访问权限不同
SaRouter.match("/api/test/hello", () -> StpUtil.checkPermission("api:test:hello"));
SaRouter.match("/api/user/info", () -> StpUtil.checkPermission("api:user:info"));
})
// setAuth方法异常处理
.setError(e -> {
// 设置错误返回格式为JSON
ServerWebExchange exchange = SaReactorSyncHolder.getContent();
exchange.getResponse().getHeaders().set("Content-Type", "application/json; charset=utf-8");
return SaResult.error(e.getMessage());
});
}
}
- Продлить предоставляемые Sa-Token
StpInterface
Интерфейс используется для получения разрешения пользователя.После того, как пользователь войдет в систему, мы будем хранить информацию о пользователе в сеансе, и информация о разрешении также будет там, поэтому код разрешения необходимо получить только из сеанса.
/**
* 自定义权限验证接口扩展
*/
@Component
public class StpInterfaceImpl implements StpInterface {
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
// 返回此 loginId 拥有的权限码列表
UserDTO userDTO = (UserDTO) StpUtil.getSession().get("userInfo");
return userDTO.getPermissionList();
}
@Override
public List<String> getRoleList(Object loginId, String loginType) {
// 返回此 loginId 拥有的角色码列表
return null;
}
}
micro-sa-token-auth
Далее давайте создадим службу аутентификации, пока вы интегрируете Sa-Token и реализуете интерфейс входа в систему, это очень просто.
- первый в
pom.xml
Добавьте связанные зависимости, в том числе зависимость Sa-Token SpringBoot, интеграцию Redis для достижения распределенногоmicro-sa-token-common
полагаться;
<dependencies>
<!-- Sa-Token 权限认证 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.24.0</version>
</dependency>
<!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.24.0</version>
</dependency>
<!-- 提供Redis连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- micro-sa-token通用依赖 -->
<dependency>
<groupId>com.macro.cloud</groupId>
<artifactId>micro-sa-token-common</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
- Далее модифицируем конфигурационный файл
application.yml
, скопируйте предыдущую конфигурацию шлюза;
spring:
redis:
database: 0
port: 6379
host: localhost
password:
# Sa-Token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: Authorization
# token有效期,单位秒,-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-head: true
- существует
UserController
Интерфейс входа определен в , а токен возвращается после успешного входа в систему. Конкретная реализация находится вUserServiceImpl
класс;
/**
* 自定义Oauth2获取令牌接口
* Created by macro on 2020/7/17.
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserServiceImpl userService;
@RequestMapping(value = "/login", method = RequestMethod.POST)
public CommonResult login(@RequestParam String username, @RequestParam String password) {
SaTokenInfo saTokenInfo = userService.login(username, password);
if (saTokenInfo == null) {
return CommonResult.validateFailed("用户名或密码错误");
}
Map<String, String> tokenMap = new HashMap<>();
tokenMap.put("token", saTokenInfo.getTokenValue());
tokenMap.put("tokenHead", saTokenInfo.getTokenName());
return CommonResult.success(tokenMap);
}
}
- существует
UserServiceImpl
В систему добавлена особая логика входа в систему: сначала проверяется пароль, после успешной проверки пароля уведомляется идентификатор пользователя входа Sa-Token, а затем информация о пользователе сохраняется непосредственно в сеансе;
/**
* 用户管理业务类
* Created by macro on 2020/6/19.
*/
@Service
public class UserServiceImpl{
private List<UserDTO> userList;
public SaTokenInfo login(String username, String password) {
SaTokenInfo saTokenInfo = null;
UserDTO userDTO = loadUserByUsername(username);
if (userDTO == null) {
return null;
}
if (!SaSecureUtil.md5(password).equals(userDTO.getPassword())) {
return null;
}
// 密码校验成功后登录,一行代码实现登录
StpUtil.login(userDTO.getId());
// 将用户信息存储到Session中
StpUtil.getSession().set("userInfo",userDTO);
// 获取当前登录用户Token信息
saTokenInfo = StpUtil.getTokenInfo();
return saTokenInfo;
}
}
- Здесь следует напомнить, что сеанс Sa-Token — это не HttpSession, который мы обычно понимаем, а механизм, подобный сеансу, реализованный сам по себе.
micro-sa-token-api
Далее давайте создадим защищенную службу API для реализации интерфейса для получения информации о пользователе для входа и тестового интерфейса, для доступа к которому требуются специальные разрешения.
- первый в
pom.xml
Добавьте связанные зависимости в, и вышеmicro-sa-token-auth
Такой же;
<dependencies>
<!-- Sa-Token 权限认证 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.24.0</version>
</dependency>
<!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.24.0</version>
</dependency>
<!-- 提供Redis连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- micro-sa-token通用依赖 -->
<dependency>
<groupId>com.macro.cloud</groupId>
<artifactId>micro-sa-token-common</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
- Далее модифицируем конфигурационный файл
application.yml
, скопируйте предыдущую конфигурацию шлюза;
spring:
redis:
database: 0
port: 6379
host: localhost
password:
# Sa-Token配置
sa-token:
# token名称 (同时也是cookie名称)
token-name: Authorization
# token有效期,单位秒,-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-head: true
- Добавьте интерфейс для получения информации о пользователе.Так как Redis используется для реализации распределенной сессии, то ее можно получить прямо из сессии.Не правда ли, очень просто!
/**
* 获取登录用户信息接口
* Created by macro on 2020/6/19.
*/
@RestController
@RequestMapping("/user")
public class UserController{
@GetMapping("/info")
public CommonResult<UserDTO> userInfo() {
UserDTO userDTO = (UserDTO) StpUtil.getSession().get("userInfo");
return CommonResult.success(userDTO);
}
}
- добавить потребность
api:test:hello
Интерфейс проверки прав доступа, предустановленныйadmin
у пользователя есть это разрешение, иmacro
Нет пользователей.
/**
* 测试接口
* Created by macro on 2020/6/19.
*/
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/hello")
public CommonResult hello() {
return CommonResult.success("Hello World.");
}
}
Демо
После создания трех служб мы используем Postman для демонстрации функции аутентификации и авторизации микрослужбы.
- Сначала запустите службы Nacos и Redis, затем запустите
micro-sa-token-gateway
,micro-sa-token-auth
иmicro-sa-token-api
Сервисы, порядок запуска не имеет значения;
- Доступ к интерфейсу входа напрямую через шлюз для получения токена.Адрес доступа:http://localhost:9201/auth/user/login
- Доступ к службам API через шлюзы,
不带Token
Доступ к интерфейсу для получения информации о пользователе невозможен, адрес доступа:http://localhost:9201/api/user/info
- Доступ к службам API через шлюзы,
带Token
Вызов интерфейса для получения информации о пользователе, доступ к которому возможен в обычном режиме;
- Чтобы получить доступ к службе API через шлюз, используйте
macro
доступ пользователяapi:test:hello
Интерфейс проверки разрешений, доступ к нему в обычном режиме невозможен, адрес доступа:http://localhost:9201/api/test/hello
- логин переключиться на
admin
пользователь, пользователь имеетapi:test:hello
орган власти;
- Чтобы получить доступ к службе API через шлюз, используйте
admin
Пользователи могут получить доступ к тестовому интерфейсу в обычном режиме.
Суммировать
По сравнению с предыдущим решением для разрешений микросервисов, использующим Spring Security, решение Sa-Token проще и элегантнее. Чтобы использовать безопасность, нам нужно определить диспетчер аутентификации, иметь дело с ситуациями без аутентификации и несанкционированного доступа, а также самостоятельно определить аутентификацию и конфигурацию сервера ресурсов, что очень громоздко в использовании. С Sa-Token вам нужно только настроить фильтры на шлюзе для реализации аутентификации и авторизации, а затем вызвать API для реализации входа и назначения разрешений. Конкретная разница может относиться к рисунку ниже.
использованная литература
Официальная документация:sa-token.dev33.cn/