Аутентификация шлюза SpringCloud

Spring Cloud

Используйте стек технологий SpringCloud для создания кластера микросервисов, тем больше компонентов можно выбрать, поскольку некоторые компоненты имеют закрытый исходный код или больше останавливаются, где основной выборspring-cloud-alibabaкак наш технологический стек.

  • Регистрация и обнаружение службы:nacos-discovery
  • Единое управление конфигурацией:nacos-config
  • Шлюз микросервисов:spring cloud gateway

Поскольку nacos сам по себе уже является полноценным сервисом, вы можете установить и использовать его напрямую, обратившись к официальной документации.Здесь мы сосредоточимся на том, как его использовать.SpringCloud GatewayРеализовать переадресацию маршрутизации и аутентификацию.

1. Микросервисная архитектура

微服务架构

  1. Все запросы проходят в первую очередьnginxзагрузить и вперед
  2. 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Требует куки для хранения

Session时序图

преимущество:

  • Простота в использовании, клиент не знает
  • Высокая безопасность
  • Улучшенная поддержка управления сессиями

недостаток:

  • Не дружит с поддержкой клиентских приложений
  • Не удается обеспечить кросс-сайтовый общий доступ
  • Реализация относительно сложная
  • Требуется поддержка файлов cookie на стороне клиента.

2. ИспользуйтеToken, выданный сервером, и хранить информацию о пользователе в redis, а клиент будет приводить ее с каждым запросом на проверку

token时序图

преимущество:

  • Поддержка совместного использования нескольких терминалов
  • Дружелюбный до многосекретной поддержки общих сеансов
  • Реализация относительно проста
  • Высокая безопасность
  • Поддержка файлов cookie не требуется

недостаток:

  • Обслуживание времени истечения сеанса более сложное
  • Сервер должен поддерживать состояние сеанса

3. ИспользуйтеJWT, выдаваемый сервером и не сохраняющий состояние сеанса, клиенту необходимо проверять легитимность каждого запроса

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 # 去掉前缀

Таким образом реализуется функция аутентификации внутреннего адреса маршрутизации.

3. Полный код

git ee.com/и Пил/Барр…

Пожалуйста, обратите внимание на мой публичный номер

请关注我的公众号