Java (swagger の MSF4J codegen) で実装された REST API と、それを説明する swagger 2 定義があります。Swagger UI は Web サーバーでホストされます。API は、インターネット上のどこかにある VM にデプロイされます。
私の問題は、swagger UI の「試してみる」機能が機能しないことです。いつも「401 Unauthorized」になります。UI から curl コマンドを取得して端末に貼り付けると、機能します。
先週、私は HTTPS または基本認証を使用せず、HTTP のみを使用しましたが、問題なく動作しました。なぜそれが機能しないのか、今ではわかりません。
swagger 定義を https に変更したため、UI は OPTIONS 要求を行います。それを実装しましたが、401 応答が返されます。
証明書は Lets Encrypt から取得され、Apache Web サーバーによって使用されます。Apache は、同じマシン上の残りの API へのプロキシです。
これが私の認証インターセプターです:
public class BasicAuthSecurityInterceptor extends AbstractBasicAuthSecurityInterceptor {
@Override
protected boolean authenticate(String username, String password) {
if (checkCredentials(username, password))
return true;
return false;
}
private boolean checkCredentials(String username, String password) {
if (username.equals("testuser"))
return BCrypt.checkpw(password, "$2a$10$iXRsLgkJg3ZZGy4utrdNyunHcamiL2RmrKHKyJAoV4kHVGhFv.d6G");
return false;
}
}
以下は API の一部です。
public abstract class DeviceApiService {
private static final Logger LOGGER = LogManager.getLogger();
public abstract Response deviceGet() throws NotFoundException;
public abstract Response deviceIdAvailableLoadGet(Integer id, Long from, Long to, String resolution)
throws NotFoundException;
public abstract Response deviceIdGet(Integer id) throws NotFoundException;
protected Response getOptionsResponse() {
String allowedOrigin = "";
try {
allowedOrigin = PropertyFileHandler.getInstance().getPropertyValueFromKey("api.cors.allowed");
} catch (IllegalArgumentException | PropertyException | IOException e) {
LOGGER.error("Could not get allowed origin.", e);
}
Response response = Response.ok().header("Allow", "GET").header("Access-Control-Allow-Origin", allowedOrigin)
.header("Access-Control-Allow-Headers", "authorization, content-type").build();
return response;
}
}
public class DeviceApi {
private final DeviceApiService delegate = DeviceApiServiceFactory.getDeviceApi();
// @formatter:off
@GET
@Produces({ "application/json" })
@io.swagger.annotations.ApiOperation(
value = "Get devices",
notes = "",
response = Device.class,
responseContainer = "List",
authorizations = { @io.swagger.annotations.Authorization(value = "basicAuth") },
tags = { "Device", }
)
@io.swagger.annotations.ApiResponses(
value = { @io.swagger.annotations.ApiResponse(
code = 200,
message = "200 OK",
response = Device.class,
responseContainer = "List")
})
public Response deviceGet() throws NotFoundException {
return delegate.deviceGet();
}
@OPTIONS
@Consumes({ "application/json" })
@Produces({ "application/json" })
@io.swagger.annotations.ApiOperation(value = "CORS support", notes = "", response = Void.class, authorizations = {
@io.swagger.annotations.Authorization(value = "basicAuth") }, tags = { "Device", })
@io.swagger.annotations.ApiResponses(value = {
@io.swagger.annotations.ApiResponse(code = 200, message = "Default response for CORS method", response = Void.class) })
public Response deviceOptions() throws NotFoundException {
return delegate.getOptionsResponse();
}
}
編集:
これは、swagger ui が作成するリクエストのヘッダーです。
Accept: text/html,application/xhtml+xm…plication/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: de,en-US;q=0.7,en;q=0.3
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: GET
Connection: keep-alive
DNT: 1
Host: api.myfancyurl.com
Origin: http://apidoc.myfancyurl.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/61.0
認証ヘッダーが欠落しているようです。リクエストを編集して、認証ヘッダーとエンコードされた資格情報を付けて再送信すると、機能します。しかし、swagger がこのヘッダーを追加しない理由はわかりません。承認なしですべてのオプション要求を受け入れる必要がありますか?