Приложение Angular 8, получающее доступ к прокси-приложению Spring Boot на локальном хосте через https

Я написал бэкенд Spring Boot и интерфейс Angular 8, которые я упаковываю вместе. Поэтому при развертывании оба используют один и тот же порт, и это прекрасно работает.

Во время разработки я хочу, чтобы оба приложения работали отдельно, и настроил это следующим образом:

application.yml

server:
  port: 10000
  servlet:
    context-path: /

DataRestController.java

@RestController
@RequestMapping("/api/data")
public class DataRestController {

  @GetMapping()
  public Collection<Data> findAll() {
    // populate result
    return result;
  }
}

data.service.ts

export class DataService {
    private url = '/api/data';

    constructor(private http: HttpClient) {
    }

    getData(): Observable<Data[]> {
        return this.http.get<Data[]>(this.url);
    }
}

Чтобы внешний интерфейс мог подключаться к внутреннему, у меня есть следующая команда, определенная в моем файле package.json:

"start": "ng serve --proxy-config proxy.conf.json --hmr --port 4201"

proxy.conf.json

{
  "/api": {
    "target": "http://localhost:10000",
    "secure": "false"
  }
}

Это все работает отлично. Я могу указать браузеру http://localhost:10000/api/data и получить данные в формате JSON. Запрос внешнего интерфейса к http://localhost:4201/api/data прозрачно перенаправляется на внутренний URL-адрес, и мое угловое приложение получает его данные.

Однако сейчас мне захотелось перейти на безопасное общение по https. Я предпринял следующие шаги:

Я создал файл PKCS12 с парой ключей, а затем извлек из него закрытый ключ и сертификат:

keytool -genkeypair -alias data -keyalg RSA -keysize 2048 -storetype PKCS12 -validity 3650 -keystore data.p12 -storepass <password>
openssl pkcs12 -info -in data.p12 -nodes -nocerts > data.key
openssl pkcs12 -info -in data.p12 -nokeys > data.cert

Я скопировал файл PKCS12 в /src/main/resources/keystore/data.p12 моего бэкенда, а два других файла в /ssl/data.* моего внешнего интерфейса.

Я добавил следующие строки в свой файл *application.yml.

server:
  ssl:
    key-store-type: pkcs12
    key-store: classpath:keystore/data.p12
    key-alias: data
    key-store-password: ENC(<jasypt encrypted password>)
    key-password: ENC(<jasypt encrypted password>)

Я также добавил файл SecurityConfig.java

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
        .requiresChannel()
        .anyRequest()
        .requiresSecure()
    ;
  }
}

Если я сейчас запущу свое серверное приложение, оно больше не будет отвечать на URL-адрес http, но ответит на https://localhost:10000/api/data (мне пришлось указать firefox принять самозаверяющий сертификат в первый раз, когда я попробовал это, но потом он работает безупречно).

Вот тут-то и начались мои проблемы, когда я попытался подключить свой интерфейс к серверу через https :-(

Я добавил следующий скрипт в package.json.

"start-ssl": "ng serve --proxy-config proxy-secure.conf.json --hmr --port 4201 --ssl true --ssl-cert ssl/data.cert --ssl-key ssl/data.key",

и создал новый файл proxy-secure.conf.json.

{
  "/api": {
    "target": "https://localhost:10000",
    "secure": "true"
  },
}

Когда я запускаю start-ssl, мое приложение теперь обслуживается https://localhost:4201 и нормально загружается в браузере. Однако, когда угловое приложение хочет получить доступ к https://localhost:4201/api/data, я получаю следующую ошибку в консоли, и браузер показывает, что для запроса возвращается статус HTTP 500.

[HPM] Error occurred while trying to proxy request /api/data from localhost:4201 to localhost (DEPTH_ZERO_SELF_SIGNED_CERT) (https://nodejs.org/api/errors.html#errors_common_system_errors)

Погуглив, я наткнулся на эту беседу на github и последовал различным советам там я попробовал следующее:

{
  "/api": {
    "target": "https://localhost:10000",
    "secure": "false"
  },
}

также как и

{
  "/api": {
    "target": "https://localhost:10000",
    "secure": "false"
    "changeOrigin": true,
  },
}

и я также изменил расширение файла, так что файл теперь proxy-secure.conf.js

var fs = require('fs');
var PROXY_CONFIG = {
  "/api": {
    "target": {
      "host": "localhost",
      "port": "10000",
      "protocol": "https:",
      "key": fs.readFileSync('ssl/data.key'),
      "cert": fs.readFileSync('ssl/data.cert')
    },
    "secure": "false",
    "rejectUnauthorized": "false",
    "changeOrigin": true,
    "logLevel": "debug"
  }
};
module.exports = PROXY_CONFIG;

Это приводит к следующему выводу при запуске приложения:

[HPM] Proxy created: /api  ->  {
  host: 'localhost',
  port: '10000',
  protocol: 'https:',
  key: <Buffer 42 61 ... <many> more bytes>,
  cert: <Buffer 42 61 ... <many> more bytes>
}
[HPM] Subscribed to http-proxy events:  [ 'error', 'close' ]

Однако, как только фронт пытается получить доступ к бэкенду, я все равно получаю ту же ошибку:

[HPM] Error occurred while trying to proxy request /api/data from localhost:4201 to localhost (DEPTH_ZERO_SELF_SIGNED_CERT) (https://nodejs.org/api/errors.html#errors_common_system_errors)

У меня заканчиваются идеи, и Google не помог. Я не могу себе представить, что я первый, кто попробовал эту установку. Можно ли в любом случае указать прокси-серверу angular либо не заботиться о моем самоподписанном сертификате, либо сказать ему доверять этому сертификату?

Если я делаю ng build --prod и mvn clean install (что благодаря maven-resources-plugin копирует папку dist внешнего интерфейса в classes/static символа, а затем запускает приложение Spring Boot с помощью java -jar data-0.0.1-SNAPSHOT.jar, все работает:

Я могу получить доступ к данным с помощью своего браузера, перейдя на https://localhost:10000/api/data и получить необработанные данные JSON. Я также могу перейти к https://localhost:10000/, чтобы запустить свое угловое приложение, и у него не возникнет проблем с прямым доступом к вышеуказанным данным JSON через https.

Таким образом, моя установка работает в производстве, но я не могу запустить ее в своей конфигурации разработки с прокси-сервером angular.


Редактировать: чтобы сообщить об использовании предложений из статьи SO. Берк Куркчуоглу связан с

Насколько я могу судить, в этой статье описывается, как включить SSL (с чем у меня не было проблем), но тем не менее попробовать стоило:

Я добавил следующее в свой angular.json

"serve": {
    "builder": "@angular-devkit/build-angular:dev-server",
    "options": {
        "browserTarget": "data:build",
        "hmrWarning": false,
        "sslKey": "ssl/data.key",
        "sslCert": "ssl/data.cert",
        "ssl": true
    }
},

Это приводит к тому, что я могу убрать параметры --ssl --ssl-cert <cert> --ssl-key <key> из моей записи ng serve в package.json, но прокси-сервер все равно выдает ту же ошибку.


person Urs Beeli    schedule 12.11.2020    source источник
comment
stackoverflow.com/ вопросы/39210467/   -  person Berk Kurkcuoglu    schedule 13.11.2020
comment
@BerkKurkcuoglu в этой статье просто объясняется, как включить SSL (то, что у меня уже сработало). Несмотря на то, что я пробовал то, что там было предложено (добавление ключа и сертификата в angular.json), прокси все еще жалуется на DEPTH_ZERO_SELF_SIGNED_CERT   -  person Urs Beeli    schedule 13.11.2020


Ответы (1)


Ну, это неудобно.

Оказывается, правильные ответы были там (на SO или Github) все время, и я было просто глупо это видеть.

Мой файл proxy.conf.json выглядел следующим образом:

{
  "/api": {
    "target": "https://localhost:10000",
    "secure": "false"
  },
}

когда это должно было быть:

{
  "/api": {
    "target": "https://localhost:10000",
    "secure": false
  },
}

(Обратите внимание на логическое значение вместо строки. Конечно, и "true", и "false" являются правдивыми, поэтому оба означают наличие true в моей конфигурации.

Теперь, когда я изменил это на false, все работает хорошо.

person Urs Beeli    schedule 05.12.2020