One IT Thing

IT業界で飯を食う為の学習系雑記

java javascript 決済

StripeとJavaで単発Web決済を一通り流してみる

投稿日:2019年10月27日 更新日:

会社仕事でも個人ビジネスでも、商品やサービスの対価として利用者に課金方法を提供したい時があるかと思います。

最もメジャーな決済方法であるクレジットカードで課金してもらう仕組みを導入したいところですが、開発システム側でクレジットカード番号を保持したり、通過させたりしてしまうと「PCI-DSS」という高難度のセキュリティ基準に従う必要が出てきます。

PCI-DSSに準拠するには堅牢なシステム構築の他、サーバ配置施設への入退館を記録、サーバルームへの入退室を記録、監視カメラの設置、他様々な要件をクリアしないと認可が下りません。

人様のカード番号を預かる訳ですから当然と言えば当然ですが、コストが掛かり過ぎて中小や個人レベルでは実現が難しいですよね。

こんな時に助け船になってくれるのが自分達の開発システムの替わりにクレジット決済をしてくれる「決済代行サービス」です。

PayPal、SPIKE、Pay.jpなど数ある決済代行サービスの中、今回はデファクトスタンダードになりつつある「Stripe」で決済までの流れを実装していきたいと思います。

Stripeとは

  • 単発課金やサブスクリプションが可能。
  • 決済手数料3.6%。
  • アプリに組み込みやすい(決済画面に遷移しなくてよい、Payment Request APIと連携可)
  • 様々な言語のライブラリが用意されている。
  • 公式ドキュメントが豊富。

手っ取り早くスマホ、PCブラウザで動作を見たい場合は以下のデモが便利です。

上記デモ開き、ブラウザのデベロッパーツールでHTMLエレメントを確認すると、カード番号入力欄はstripeサーバから提供されるHTMLソースをiframeで読み込んでいて、こちらが開発するHTMLソースとは分離されていることが確認できます。フロントエンド側でも非保持が出来ていそうです。

検証構成

色んな構成形態をとることが出来るStripeですが今回はこんな感じで単純な実装をしてみます。

カード番号に対する「トークン」を発行してもらうことでPCI-DSS準拠を回避します。開発するシステムではユーザの選択したカード番号を知ることは出来ません。

商品が渡せなかった場合は決済をしないような処理も出来るので、GooglePlayやAppStoreのアプリ内課金より柔軟でいいですね。

検証環境

  • Windows 10
  • Eclipse 2019-03
  • Java8

localhostで動作確認する分にはHTTP環境でOKです。スマホなど外部ホストから接続する時はHTTPS環境が必要になります。

HTTPS環境がない場合はngrokで代替すればOKです。

シンプルに実装して決済まで確認してみる

Stripeのクレジットカード入力画面をJavascriptで表示する場合、主に3つの方法があります。

  1. クレジット入力画面をカスタマイズ出来るStripe Element
  2. 出来合いのダイアログを表示出来るcheckout.js
  3. W3C標準のPayment Request APIと連携するPayment Request Button

今回は決済完了までの動作確認をするだけなので、最も簡単な2で決済までやってみます。

実戦に導入するなら、以前ブラウザに入力したことがあるカードが候補に出る3にするか、ダイアログではなくページに溶け込ませることが出来る1も検討に入れます。

1.stripe.comでアカウントを作る

stripe.comで「今すぐ始める」ボタンをクリックするとアカウントが作れます。テスト環境を使うだけなら数分で終わります。このあたりの簡単さもStripeのシェア拡大に一役買ってそうですね。

ログインしてダッシュボードに入り、「テストAPIキー」の公開可能キーとシークレットキーを確認しておきます。後でプログラムから指定する為です。

2.SpringBootプロジェクトを作成

フロントエンドのHTML、バックエンドHTTPサーバを作る為のプロジェクトをSpringBootで適当に作っておきます。(作成したことがなければ以下参照)

3.フロントエンドHTMLを作成

公式ドキュメントを参考にしながら実装していきます。

/src/main/resource/static/stripe-checkout.htmlを作成して以下を記述します。data-keyには先程作ったアカウントの「公開可能キー」を指定します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Stripe checkout.jsの動作確認</title>
</head>
<body>
<form action="/pay" method="POST">
  <script
    src="https://checkout.stripe.com/checkout.js"
    class="stripe-button"
    data-key="pk_test_xxxxxxxxxxxxxxxxxxxxxxxxx"
    data-name="Tシャツ"
    data-description="コットンTシャツ"
    data-amount="500"
    data-currency="jpy">
  </script>
</form>
</body>
</html>

http://localhost:8080/stripe-checkout.htmlにアクセスするとカード番号入力ダイアログが表示されます。「TEST MODE」ボタンを押してテスト用ダミーカード番号を確認、指定してみましょう。

ただこの状態でPayボタンをクリックしても、formアクションのPOST先「/pay」が無いのでエラーになってしまいます。Javaでサーバ側を実装していきましょう。

4.バックエンドJavaを実装

mvnrepositoryで「stripe-java」の最新バージョンを探してpom.xmlに依存を追加します。

このjarを使うとStripeサーバに対して決済依頼やトークンのチェックをリクエストすることが出来るようになります。

		<dependency>
		    <groupId>com.stripe</groupId>
		    <artifactId>stripe-java</artifactId>
		    <version>14.3.0</version>
		</dependency>

Spring MVCで/payを実装します。Stripe.apiKeyにはご自分のアカウントの「シークレットキー」を指定してください。

package com.example.demo;

import java.util.HashMap;
import java.util.Map;

import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.stripe.Stripe;
import com.stripe.exception.StripeException;
import com.stripe.model.Charge;

@Controller
public class DemoServer {

	@RequestMapping(path = "/pay", method = { RequestMethod.POST })
    public ResponseEntity charge(
            @RequestParam("stripeToken") String stripeToken,
            @RequestParam("stripeTokenType") String stripeTokenType,
            @RequestParam("stripeEmail") String stripeEmail)
    {

        Stripe.apiKey = "sk_test_xxxxxxxxxxxxxxxxxxxxxxxx";

        Map<String, Object> chargeMap = new HashMap<String, Object>();
        chargeMap.put("amount", 500);
        chargeMap.put("description", "コットンTシャツ");
        chargeMap.put("currency", "jpy");
        chargeMap.put("source", stripeToken);

        try {
            Charge charge = Charge.create(chargeMap);
            System.out.println(charge);
        } catch (StripeException e) {
            e.printStackTrace();
        }

        ResponseEntity response = ResponseEntity.ok().build();

        return response;
    }

実装完了です。

動作確認

再度 http://localhost:8080/stripe-checkout.html にアクセスしてPayボタンをクリックしてみると今度は正常に終了し、EclipseのコンソールにはStripeサーバから決済が完了した旨のJSONが返却されているはずです。

<com.stripe.model.Charge@1751915628 id=ch_1FYCH3HZxxxxxxxxxxyY1NS> JSON: {
  "alternate_statement_descriptors": null,
  "amount": 500,
  "amount_refunded": 0,
  "application": null,
  "application_fee": null,
  "application_fee_amount": null,

(snip)

ブラウザでStripeのダッシュボードを開いて決済が完了しているか見てみましょう。左メニュー「残高」→「取引」で確認できます。

決済されていました。手数料3.6%なので500円の内18円がStripeに渡っていますね。
(テスト環境なので実際に入金はされていません)

Stripeダッシュボードで決済が完了していることが確認できました。

まとめと課題

テスト環境とはいえ少ない労力でクレジットカード課金を実装することが出来ました。

本番に移行する際はサイトURLの登録や審査を通し、発行された本番APIキーに切り替えるだけです。ほんとにシンプルで便利ですね。

ただ今回の動作確認は最も簡単な実装なので色々課題や要望が残ります。

  • FORM送信だとページ遷移してしまったりトークン取得とサーバへの決済依頼が同時に発生して使いづらいのでAjax送信にしたい。
  • サーバ側もそれに合わせてJSON受信するRESTにしたい。
  • 課金ダイアログはW3C標準APIのPayment Request APIにしたい。
  • Google Pay、Apple Payを使ってクレジットカード選択を楽にしたい。

次回はこれらをやってみたいと思います。

-java, javascript, 決済
-

執筆者:

関連記事

JavaでRSA暗号を使う際にCRYPTREC暗号リストに足元をすくわれる可能性を回避する

標準的な暗号しか使わないケースでもJavaでRSAを使う時はBouncyCastleを入れておいた方が無難、という話です。 “ECB”という文字列がプログラム中にあると監査に引 …

SpringBootアプリにBootstrap4を追加(WebJars使用)

SpringBootにCSSやJSを追加する場合は概ね以下のパターンがあるんじゃないかと思います。(bowerはもう使わない方向で) CDNで外部から読み込む<script src=&#8221 …

Apple PayのMerchant Doamin設定がPendingになり、Verifiedにならなかった原因

開発しているWebシステム上でApple Payによるクレジットカード選択が出来るようにするには「Apple Developer Program」で「Merchant Domain」を設定します。 & …

Javascript(暗号化JSライブラリ「Forge」)とp12ファイルで署名値を作成、Javaで検証する

前回、送信データの改ざんを検知する為、簡易的なセキュリティトークンであるPKCS#12形式のファイルを作成しました。  One IT Thing開発用のPKCS#12ファイルをOpenSSL …

Stripe+Java+Payment Request APIでApple Pay、Google Payを使ったテストWeb決済をしてみる

自分で作ったサービスを運用してチャリンチャリンしたい・・・エンジニアならこんな夢、一度は見たことがあるんじゃないでしょうか。 夢を実現する為、以前Stripeのcheckout.jsを使ったテストWe …

 

shingo.nakanishi
 

東京在勤、職歴20年越え中年ITエンジニアです。まだ開発現場で頑張っています。

19歳(1996年)から書き始めた個人日記が5,000日を超え、残りの人生は発信をして行きたいと思い、令和元日からこのサイトを開始しました。勉強と試行錯誤をしながら、自分が経験したIT関連情報を投稿しています。

私と同じく、今後IT業界で生計を立てて行きたいと考えている方や、技術共有したいけどフリーランスで孤独、といった方と一緒に成長、知識共有して行けたら楽しいな、と思っています。