コンテンツにスキップ

Java と Kotlin

パッケージ: jp.co.tenon:tenon-auth-sdk:1.0.0(Java 17 以降)。

  • 依存関係: org.jspecify:jspecify のアノテーションのみ。Kotlin から null になりうる値がわかります。
  • スレッド: クライアントはスレッドセーフなので、シングルトン(Spring の @Bean)にしてください。

ダウンロードから jar を取得し、SHA-256 を確認して追加します:

dependencies {
implementation(files("libs/tenon-auth-sdk-1.0.0.jar"))
implementation("org.jspecify:jspecify:1.0.0")
}
@Bean
TenonAuthClient tenonAuth(@Value("${tenon-auth.url}") String url, @Value("${tenon-auth.api-key}") String apiKey) {
return TenonAuthClient.builder().baseUrl(url).apiKey(apiKey).build();
}

オプション:

  • connectTimeout(5秒)と readTimeout(30秒)
  • header(name, value)(プロキシ用など)
  • httpClient(HttpClient)(独自のプロキシや社内 CA)

localhost 以外への http:// と、アプリケーションの API キー(tnk_…)以外のキーは拒否します。

@PostMapping("/login")
String login(LoginForm form, HttpServletRequest request, HttpSession session) {
Account account = accounts.checkPassword(form.username(), form.password()); // あなたの処理
SecondStep step;
try {
step = tenonAuth.beginSecondStep(account.id(), new SignInContext(request.getRemoteAddr(), request.getHeader("User-Agent")),
cookieValue(request, "tenon_device"), "ja");
} catch (TenonAuthUnavailableException e) {
return emergency.allows(account) ? signIn(session, account) : "login-unavailable"; // フェイルクローズ
}
session.setAttribute("secondStep", step); // SecondStep は Serializable
return switch (step.kind()) {
case CODE_ENTRY -> "redirect:/login/code";
case PUSH_WAIT -> "redirect:/login/approve";
case RECOVERY_ONLY -> "redirect:/login/recover";
case TRUSTED, NO_METHOD -> signIn(session, account);
};
}
@PostMapping("/login/code")
String code(@RequestParam String code, HttpSession session) {
SecondStep step = (SecondStep) session.getAttribute("secondStep");
SecondStepResult result = tenonAuth.completeWithCode(step, code);
return switch (result.status()) {
case APPROVED -> signIn(session, step);
case WRONG_CODE -> "redirect:/login/code?wrong=" + result.attemptsRemaining();
default -> "redirect:/login"; // FAILED、EXPIRED:やり直し
};
}

待機画面では2秒ごとに tenonAuth.pollApproval(step)、リカバリー画面では tenonAuth.completeWithRecoveryCode(step, code) を呼びます。

レコードはプロパティとして読め(step.kind、user.id)、null 許容も型でわかります:

val step = tenonAuth.beginSecondStep(account.id, SignInContext(ip, userAgent))
val number: Int? = step.number

すべての呼び出しは、TenonAuthException のサブクラスを投げます:

  • TenonAuthUnavailableException
  • ApiKeyRejectedException、ForbiddenException
  • InvalidRequestException、NotFoundException、InvalidCodeException
  • FactorLockedException、TooManyRequestsException
  • EmailRefusedException、EmailUnavailableException
  • ConflictException

エラーを参照してください。