Используйте стек технологий SpringCloud для создания кластера микросервисов, тем больше компонентов можно выбрать, поскольку некоторые компоненты имеют закрытый исходный код или больше останавливаются, где основной выборspring-cloud-alibaba
как наш технологический стек.
- Регистрация и обнаружение службы:
nacos-discovery
- Единое управление конфигурацией:
nacos-config
- Шлюз микросервисов:
spring cloud gateway
Поскольку nacos сам по себе уже является полноценным сервисом, вы можете установить и использовать его напрямую, обратившись к официальной документации.Здесь мы сосредоточимся на том, как его использовать.SpringCloud Gateway
Реализовать переадресацию маршрутизации и аутентификацию.
1. Микросервисная архитектура
- Все запросы проходят в первую очередь
nginx
загрузить и вперед -
API Gateway
Отвечает за переадресацию маршрутизации и аутентификацию личности в микросервисах.
2. Реализовать маршрутизацию и переадресацию
1. Представьте пакет шлюза
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
Следует отметить, что: если сообщение об ошибке при запуске, она указывает на то, что SpringMVC, обнаруженный в зависимости, не совместим с шлюзом и должен быть удаленspring-boot-starter-web
Связанная ссылка
**********************************************************
Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. Please remove spring-boot-starter-web dependency.
**********************************************************
2. Добавьте стартовый класс
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
-
@EnableDiscoveryClient
Используется для регистрации и обнаружения службы в кластере.
3. Настройте таблицу маршрутизации
Конфигурационный файл — лучший выборYAML, структура понятна и легко читается
spring:
application:
name: cloud-api #服务名
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # nacos服务器地址
gateway:
routes:
- id: cloud-user
uri: lb://cloud-user # 后端服务名
predicates:
- Path=/user/** # 路由地址
filters:
- StripPrefix=1 # 去掉前缀
server:
port: 8000
# 用于actuator暴露监控指标
management:
endpoints:
web:
exposure:
include: "*"
-
StripPrefix=1
Он используется для удаления адреса префикса во время переадресации маршрута. Если префикс отсутствует, префикс будет переадресован на сервис Backend, например:
Адрес запроса:http://localhost:8000/user/home
без добавленияStripPrefix
Когда переадресация на адрес внутренней службы:http://{cloud-user}/user/home, в противном случаеhttp://{cloud-user}/home
-
management
Настроено для предоставления метрик мониторинга, может быть запрошеноhttp://localhost:8000/actuator/gateway/routesПолучить все сопоставленные маршруты
3. Реализуйте аутентификацию личности
В распределенных системах обычно используются три метода аутентификации:
1. ИспользуйтеSession, быть пригодным для использованияspring security
реализоватьSessionуправление, используя Redis для хранения состояния сеанса,sessionIDТребует куки для хранения
преимущество:
- Простота в использовании, клиент не знает
- Высокая безопасность
- Улучшенная поддержка управления сессиями
недостаток:
- Не дружит с поддержкой клиентских приложений
- Не удается обеспечить кросс-сайтовый общий доступ
- Реализация относительно сложная
- Требуется поддержка файлов cookie на стороне клиента.
2. ИспользуйтеToken, выданный сервером, и хранить информацию о пользователе в redis, а клиент будет приводить ее с каждым запросом на проверку
преимущество:
- Поддержка совместного использования нескольких терминалов
- Дружелюбный до многосекретной поддержки общих сеансов
- Реализация относительно проста
- Высокая безопасность
- Поддержка файлов cookie не требуется
недостаток:
- Обслуживание времени истечения сеанса более сложное
- Сервер должен поддерживать состояние сеанса
3. ИспользуйтеJWT, выдаваемый сервером и не сохраняющий состояние сеанса, клиенту необходимо проверять легитимность каждого запроса
преимущество:
- Поддержка совместного использования нескольких терминалов
- Дружественная поддержка общих сеансов с несколькими терминалами
- Сервер не имеет состояния сеанса
- Поддержка файлов cookie не требуется
- Загруженные данные автомобиля
недостаток:
- Обслуживание времени истечения сеанса более сложное
- Менее безопасный по умолчанию
- После выдачи он не может быть отозван или отзыв сложен.
Простая проверка токена
Этот пример токена генерируется случайным кодом случайным образом, не используйте алгоритмы для проверки, поэтому можно заставить клиента использовать исчерпывающий токен, постоянно опрашивая Redis, подверженный риску. Алгоритм может использоваться в производственной среде, должен быть выдан токен (например, шифрование и дешифрование, действительная временная метка и т. д.), чтобы свести к минимуму воздействие подделки на сервер токенов.
1. Пользователь входит в систему, чтобы сохранить состояние сеанса.
@Service
public class Session {
@Autowired
private RedisTemplate<String, String> redisTemplate;
Long expireTime = 10800L;
/**
* 保存session
* @param loginUser
*/
public void saveSession(LoginUser loginUser) {
String key = String.format("login:user:%s", loginUser.userToken);
redisTemplate.opsForValue().set(key, JSON.toJSONString(loginUser),
expireTime, TimeUnit.SECONDS);
}
/**
* 获取session
* @param token
* @return
*/
public LoginUser getSession(String token){
String key = String.format("login:user:%s", token);
String s = redisTemplate.opsForValue().get(key);
if (Strings.isEmpty(s)){
return null;
}
return JSON.parseObject(s, LoginUser.class);
}
}
При сохранении состояния сеанса вам необходимо установить время истечения срока действия, которое не должно быть слишком длинным или слишком коротким. Например, подумать о том, как обновить время истечения сеанса.
2. УвеличениеAuthCheckFilter, перехватывать запросы маршрутизации
@Slf4j
@Component
public class AuthCheckFilter extends AbstractGatewayFilterFactory {
@Autowired
private Session session;
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 1. 获取token
String token = request.getHeaders().getFirst("token");
log.info("当前请求的url:{}, method:{}", request.getURI().getPath(), request.getMethodValue());
if (Strings.isEmpty(token)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 2. 验证用户是否已登陆
LoginUser loginUser = this.session.getSession(token);
if (loginUser == null) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 3. 将用户名传递给后端服务
ServerWebExchange build;
try {
ServerHttpRequest host = exchange.getRequest().mutate()
.header("X-User-Name", loginUser.userName)
// 中文字符需要编码
.header("X-Real-Name", URLEncoder.encode(loginUser.realName, "utf-8"))
.build();
build = exchange.mutate().request(host).build();
} catch (UnsupportedEncodingException e) {
build = exchange;
}
return chain.filter(build);
};
}
}
Этот перехватчик используется для проверки того, был ли выполнен вход в систему, в противном случае он возвращает401
состояние и передавать информацию о сеансе пользователя внутренним службам.
3. Настройте фильтр
Настройте фильтры маршрутизации, которые необходимо аутентифицировать, в файле конфигурации yml проекта шлюза:AuthCheckFilter
spring:
gateway:
routes:
- id: cloud-user
uri: lb://cloud-user # 后端服务名
predicates:
- Path=/user/** # 路由地址
filters:
- name: AuthCheckFilter #会话验证
- StripPrefix=1 # 去掉前缀
Таким образом реализуется функция аутентификации внутреннего адреса маршрутизации.