set lines 1000 set serveroutput on declare l_now timestamp; l_secret varchar2(32) := 'secret!'; l_username varchar2(32) := 'TESTUSER'; l_jwt varchar2(32767); l_jwt_token apex_jwt.t_token; l_jwt_t apex_t_varchar2; l_header_json json_object_t; l_header_str varchar2(200); l_header_base64 varchar2(400); l_payload_json json_object_t; l_payload_str varchar2(200); l_payload_base64 varchar2(800); l_token varchar2(1000); l_hmac varchar2(1000); -- Unix時間の取得 function unixtime(p_timestamp in timestamp) return pls_integer is l_date date; l_epoc number; begin l_date := sys_extract_utc(p_timestamp); l_epoc := l_date - date'1970-01-01'; return l_epoc * 24 * 60 * 60; end unixtime; -- Base64のデコード function from_base64(t in varchar2) return varchar2 is begin return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(t))); end from_base64; -- Base64のエンコード function to_base64(t in varchar2) return varchar2 is l_base64 varchar2(32767); begin l_base64 := utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t))); l_base64 := replace(l_base64, chr(13)||chr(10), ''); return l_base64; end to_base64; begin -- 共通で使用する現在時刻 l_now := current_timestamp; dbms_output.put_line('Current Timestamp = ' || l_now || ', unixtime = ' || unixtime(l_now)); -- APEX_JWTパッケージを使用しJWTの作成 -- Using Oracle APEX provided package APEX_JWT l_jwt := apex_jwt.encode ( p_iss => 'sqlplus', p_aud => 'APEX', p_sub => l_username, p_iat_ts => l_now, p_exp_sec => 10, p_signature_key => sys.utl_raw.cast_to_raw(l_secret)); -- 生成したJava Web Token l_jwt_t := apex_string.split(l_jwt, '.'); dbms_output.put_line('APEX_JWT.encode ==========================='); dbms_output.put_line('Header = ' || l_jwt_t(1)); dbms_output.put_line('Payload = ' || l_jwt_t(2)); dbms_output.put_line('Signature = ' || l_jwt_t(3)); -- JWTをデコードし、内容を確認する。 l_jwt_token := apex_jwt.decode ( p_value => l_jwt, p_signature_key => sys.utl_raw.cast_to_raw(l_secret) ); -- dbms_output.put_line('APEX_JWT.decode ==========================='); dbms_output.put_line('Header = ' || trim(l_jwt_token.header) ); dbms_output.put_line('Payload = ' || trim(l_jwt_token.payload) ); dbms_output.put_line('Signature = ' || trim(l_jwt_token.signature) ); -- ヘッダーを手作業で生成する。 dbms_output.put_line('Hand made =================================='); l_header_json := json_object_t(); l_header_json.put('alg','HS256'); l_header_json.put('typ','JWT'); l_header_str := l_header_json.to_string(); l_header_base64 := to_base64(l_header_str); dbms_output.put_line('Header = ' || l_header_str); dbms_output.put_line('Header = ' || l_header_base64); -- ペイロードを手作業で作成する。 l_payload_json := json_object_t(); l_payload_json.put('iss','sqlplus'); l_payload_json.put('sub',l_username); l_payload_json.put('aud','APEX'); l_payload_json.put('iat',unixtime(l_now)); l_payload_json.put('exp',unixtime(l_now)+10); l_payload_str := l_payload_json.to_string(); l_payload_base64 := to_base64(l_payload_str); dbms_output.put_line('Payload = ' || l_payload_str); dbms_output.put_line('Payload = ' || l_payload_base64); -- シグネチャを手作業で作成する。 l_token := l_header_base64 || '.' || l_payload_base64; l_hmac := utl_raw.cast_to_varchar2(utl_encode.base64_encode(dbms_crypto.mac( utl_raw.cast_to_raw(l_token), dbms_crypto.HMAC_SH256, utl_raw.cast_to_raw(l_secret) ))); l_hmac := trim(translate(l_hmac, '+/=', '-_ ')); dbms_output.put_line('Signature = ' || l_hmac); end; /上記の実行結果は以下のような感じです。時刻が毎回変わるため、同じ結果は生成されないです。
Current Timestamp = 12-MAR-20 04.29.05.616729 PM, unixtime = 1583998145 APEX_JWT.encode =========================== Header = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 Payload = eyJpc3MiOiJzcWxwbHVzIiwic3ViIjoiVEVTVFVTRVIiLCJhdWQiOiJBUEVYIiwiaWF0IjoxNTgzOTk4MTQ1LCJleHAiOjE1ODM5OTgxNTV9 Signature = fgjlxE-JLcZdcvU4D_vqP9xX29G8lgC6w4zzifWCPuU APEX_JWT.decode =========================== Header = {"alg":"HS256","typ":"JWT"} Payload = {"iss":"sqlplus","sub":"TESTUSER","aud":"APEX","iat":1583998145,"exp":1583998155} Signature = fgjlxE-JLcZdcvU4D_vqP9xX29G8lgC6w4zzifWCPuU Hand made ================================== Header = {"alg":"HS256","typ":"JWT"} Header = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 Payload = {"iss":"sqlplus","sub":"TESTUSER","aud":"APEX","iat":1583998145,"exp":1583998155} Payload = eyJpc3MiOiJzcWxwbHVzIiwic3ViIjoiVEVTVFVTRVIiLCJhdWQiOiJBUEVYIiwiaWF0IjoxNTgzOTk4MTQ1LCJleHAiOjE1ODM5OTgxNTV9 Signature = fgjlxE-JLcZdcvU4D_vqP9xX29G8lgC6w4zzifWCPuUBase64変換はこちらの記事、Base64の変換結果から改行を除く方法はこちらの記事、Unix時間の取得はこちらの記事、それ以外にはこちらの記事も参考にさせていただきました。ありがたいことです。もちろん、RFC 7519とRFC 4648も。
完