{"id":11748,"date":"2024-02-25T22:07:37","date_gmt":"2024-02-25T13:07:37","guid":{"rendered":"https:\/\/www.webcyou.com\/?p=11748"},"modified":"2024-02-25T22:07:56","modified_gmt":"2024-02-25T13:07:56","slug":"rust-actix-web-jwt-%e8%aa%8d%e8%a8%bc%e8%aa%8d%e5%8f%af-api%e3%81%ae%e4%bd%9c%e6%88%90","status":"publish","type":"post","link":"https:\/\/www.webcyou.com\/?p=11748","title":{"rendered":"Rust &#8211; Actix Web JWT \u8a8d\u8a3c\u8a8d\u53ef API\u306e\u4f5c\u6210"},"content":{"rendered":"\n<p>\u3069\u3082\u3067\u3059\u3002<\/p>\n<p>\u3044\u3084\u3041\u3001\u3082\u30462\u6708\u3082\u7d42\u308f\u308b\u3068\u3044\u3046\u3053\u3068\u3067\u3001\u672c\u5f53\u306b\u6642\u9593\u306e\u6d41\u308c\u3092\u65e9\u304f\u611f\u3058\u3066\u304a\u308a\u307e\u3059\u3002<\/p>\n<p>\u696d\u52d9\u3067\u306fRust\u3067\u30bd\u30d5\u30c8\u30a6\u30a7\u30a2\u3092\u4f5c\u6210\u3057\u3066\u304a\u308a\u307e\u3059\u304c\u3001\u8da3\u5473\u3067\u306fRust\u3067\u30b5\u30fc\u30d0\u30fc\u958b\u767a\u3082\u884c\u3063\u3066\u3044\u307e\u3057\u3066\u3001\u4eca\u56de\u3082\u524d\u56de\u306b\u5f15\u304d\u7d9a\u304dRust\u306e\u30b5\u30fc\u30d0\u30fc\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u3067\u3042\u308b\u3001Actix Web\u306b\u3064\u3044\u3066\u30c4\u30e9\u30c4\u30e9\u3068\u66f8\u3044\u3066\u884c\u3053\u3046\u304b\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n<p>\u4eca\u56de\u306f\u3001Actix Web\u3092\u7528\u3044\u305f\u7c21\u6613\u306aJWT\u8a8d\u8a3c\u8a8d\u53ef\u306eAPI\u3092\u4f5c\u6210\u3057\u3066\u3044\u3053\u3046\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n<h4><!-- notionvc: a71f8701-a8c5-4dc5-bf1f-c26127682b73 -->JWT\u306b\u95a2\u3057\u3066<!-- notionvc: 672bab32-996f-4d4e-92c2-2956d1327773 --><\/h4>\n<p>\u307e\u305a\u3001JWT\u306b\u95a2\u3057\u3066\u8efd\u304f\u3054\u8aac\u660e\u3092\u3068\u3002<\/p>\n<p>JWT\uff08JSON Web Token\uff09\u306f\u3001Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3084\u30b5\u30fc\u30d3\u30b9\u9593\u3067\u306e\u5b89\u5168\u306a\u60c5\u5831\u306e\u4f1d\u9054\u3092\u76ee\u7684\u3068\u3057\u305f\u3001\u30b3\u30f3\u30d1\u30af\u30c8\u3067\u81ea\u5df1\u5b8c\u7d50\u578b\u306e\u30c8\u30fc\u30af\u30f3\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u3067\u3059\u3002\u4e3b\u306b\u8a8d\u8a3c\u3084\u60c5\u5831\u4ea4\u63db\u306b\u4f7f\u7528\u3055\u308c\u307e\u3059\u3002JWT\u306f\u3001JSON\u5f62\u5f0f\u3067\u69cb\u9020\u5316\u3055\u308c\u305f\u30c7\u30fc\u30bf\u3092\u542b\u3093\u3067\u304a\u308a\u3001\u4ee5\u4e0b\u306e\u4e09\u90e8\u5206\u304b\u3089\u69cb\u6210\u3055\u308c\u3066\u3044\u307e\u3059\u3002<\/p>\n<p><!-- notionvc: 1cad87bd-7e61-4b46-98a5-052f75e3e6c1 --><\/p>\n<ol>\n<li><strong>\u30d8\u30c3\u30c0\u30fc\uff08Header\uff09<\/strong>:\n<ul>\n<li>\u30c8\u30fc\u30af\u30f3\u306e\u30bf\u30a4\u30d7\uff08\u901a\u5e38\u306fJWT\uff09\u3068\u3001\u4f7f\u7528\u3055\u308c\u3066\u3044\u308b\u7f72\u540d\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0\uff08\u4f8b\u3048\u3070\u3001HMAC SHA256\u3084RSA\uff09\u304c\u542b\u307e\u308c\u307e\u3059\u3002<\/li>\n<li>JSON\u5f62\u5f0f\u3067\u8a18\u8ff0\u3055\u308c\u3001Base64Url\u65b9\u5f0f\u3067\u30a8\u30f3\u30b3\u30fc\u30c9\u3055\u308c\u307e\u3059\u3002<\/li>\n<\/ul>\n<\/li>\n<li><strong>\u30da\u30a4\u30ed\u30fc\u30c9\uff08Payload\uff09<\/strong>:\n<ul>\n<li>\u30c8\u30fc\u30af\u30f3\u306b\u542b\u3081\u308b\u5b9f\u969b\u306e\u30c7\u30fc\u30bf\u304c\u542b\u307e\u308c\u307e\u3059\u3002<\/li>\n<li>\u901a\u5e38\u3001\u30e6\u30fc\u30b6\u30fc\u8b58\u5225\u60c5\u5831\u3084\u6709\u52b9\u671f\u9650\u306a\u3069\u306e\u30af\u30ec\u30fc\u30e0\uff08\u4e3b\u5f35\uff09\u304c\u542b\u307e\u308c\u307e\u3059\u3002<\/li>\n<li>\u30af\u30ec\u30fc\u30e0\u306f\u4e09\u7a2e\u985e\u306b\u5206\u3051\u3089\u308c\u307e\u3059\uff1a\u767b\u9332\u6e08\u307f\u30af\u30ec\u30fc\u30e0\uff08\u4e88\u7d04\u3055\u308c\u305f\u540d\u524d\u306e\u30bb\u30c3\u30c8\uff09\u3001\u516c\u958b\u30af\u30ec\u30fc\u30e0\uff08\u5171\u6709\u60c5\u5831\u7528\uff09\u3001\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8\u30af\u30ec\u30fc\u30e0\uff08\u9001\u4fe1\u8005\u3068\u53d7\u4fe1\u8005\u306e\u9593\u3067\u5408\u610f\u3057\u305f\u60c5\u5831\uff09\u3002<\/li>\n<li>\u3053\u308c\u3082JSON\u5f62\u5f0f\u3067\u8a18\u8ff0\u3055\u308c\u3001Base64Url\u65b9\u5f0f\u3067\u30a8\u30f3\u30b3\u30fc\u30c9\u3055\u308c\u307e\u3059\u3002<\/li>\n<\/ul>\n<\/li>\n<li><strong>\u7f72\u540d\uff08Signature\uff09<\/strong>:\n<ul>\n<li>JWT\u306e\u6574\u5408\u6027\u3068\u691c\u8a3c\u53ef\u80fd\u6027\u3092\u78ba\u4fdd\u3059\u308b\u305f\u3081\u306e\u7f72\u540d\u304c\u542b\u307e\u308c\u307e\u3059\u3002<\/li>\n<li>\u30d8\u30c3\u30c0\u30fc\u306e\u30a8\u30f3\u30b3\u30fc\u30c9\u3055\u308c\u305f\u5024\u3001\u30da\u30a4\u30ed\u30fc\u30c9\u306e\u30a8\u30f3\u30b3\u30fc\u30c9\u3055\u308c\u305f\u5024\u3001\u79d8\u5bc6\u9375\uff08\u307e\u305f\u306f\u516c\u958b\u9375\/\u79d8\u5bc6\u9375\u30da\u30a2\uff09\u3092\u4f7f\u7528\u3057\u3066\u751f\u6210\u3055\u308c\u307e\u3059\u3002<\/li>\n<li>\u7f72\u540d\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0\u306f\u30d8\u30c3\u30c0\u30fc\u3067\u6307\u5b9a\u3055\u308c\u305f\u3082\u306e\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p><!-- notionvc: b307e4d3-3f07-499d-9e46-2df444610ad7 --><\/p>\n<p>JWT\u306f\u3001\u305d\u306e\u30b3\u30f3\u30d1\u30af\u30c8\u306a\u5f62\u5f0f\u3068\u81ea\u5df1\u5b8c\u7d50\u578b\u306e\u7279\u6027\u306b\u3088\u308a\u3001URL\u3001POST\u30d1\u30e9\u30e1\u30fc\u30bf\u3001HTTP\u30d8\u30c3\u30c0\u30fc\u306a\u3069\u3092\u4ecb\u3057\u3066\u7c21\u5358\u306b\u9001\u4fe1\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u307e\u305f\u3001\u7f72\u540d\u3055\u308c\u3066\u3044\u308b\u305f\u3081\u3001\u30c8\u30fc\u30af\u30f3\u306e\u5185\u5bb9\u304c\u9014\u4e2d\u3067\u6539\u3056\u3093\u3055\u308c\u308b\u3053\u3068\u306f\u306a\u304f\u3001\u9001\u4fe1\u8005\u304c\u30c8\u30fc\u30af\u30f3\u306e\u5185\u5bb9\u3092\u4fdd\u8a3c\u3057\u307e\u3059\u3002\u305f\u3060\u3057\u3001\u30da\u30a4\u30ed\u30fc\u30c9\u306f\u30a8\u30f3\u30b3\u30fc\u30c9\u3055\u308c\u3066\u3044\u308b\u3060\u3051\u3067\u6697\u53f7\u5316\u3055\u308c\u3066\u3044\u308b\u308f\u3051\u3067\u306f\u306a\u3044\u305f\u3081\u3001\u6a5f\u5bc6\u6027\u304c\u5fc5\u8981\u306a\u60c5\u5831\u306f\u542b\u3081\u308b\u3079\u304d\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002<\/p>\n<p>JWT\u306f\u3001\u7279\u306b\u30b7\u30f3\u30b0\u30eb\u30b5\u30a4\u30f3\u30aa\u30f3(SSO)\u3084OAuth\u306a\u3069\u306e\u8a8d\u8a3c\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u3067\u5e83\u304f\u4f7f\u308f\u308c\u3066\u3044\u307e\u3059\u3002\u3068\u3044\u3046\u8a33\u3067\u3001\u6628\u4eca\u3067\u306f\u69d8\u3005\u306a\u30b7\u30fc\u30f3\u3067\u5e45\u5e83\u304f\u7528\u3044\u3089\u308c\u308bJWT\u3092\u7528\u3044\u3066API\u3092\u4f5c\u6210\u3057\u3066\u3044\u304d\u307e\u3057\u3087\u3046\u3002<\/p>\n<h4><!-- notionvc: 368fb974-ef76-4c15-92f1-d59d0bdab9da -->\u30af\u30ec\u30fc\u30c8\u306a\u3069\u6e96\u5099<!-- notionvc: 274cf477-01c9-4d31-acc5-1b1bdb2bc696 --><\/h4>\n<p>\u305d\u308c\u3067\u306f\u3001\u65e9\u901f\u4f5c\u6210\u3057\u3066\u3044\u304d\u307e\u3057\u3087\u3046\u3002<\/p>\n<p>\u4eca\u56de\u306e\u4f5c\u6210\u3057\u305f\u30bd\u30fc\u30b9\u306f\u3053\u3061\u3089\u3068\u306a\u308a\u307e\u3059\u3002<\/p>\n<p>\u30bd\u30fc\u30b9\u3060\u3051\u78ba\u8a8d\u3057\u305f\u3044\u65b9\u306f\u3053\u3061\u3089\u3092\u3054\u53c2\u7167\u304f\u3060\u3055\u3044\u3002<\/p>\n<p><a href=\"https:\/\/github.com\/rust-game-samples\/actix_web_sample\/tree\/main\/jwt_auth\">https:\/\/github.com\/rust-game-samples\/actix_web_sample\/tree\/main\/jwt_auth<\/a><\/p>\n<p>\u4eca\u56de\u4f7f\u7528\u3059\u308bcrate<\/p>\n<p><!-- notionvc: 98cd1dfd-ada3-4305-baf1-eca9413e7c08 --><\/p>\n<p><span class=\"notion-enable-hover\" data-token-index=\"0\">Cargo.toml<\/span><!-- notionvc: 10aed833-2933-4f0c-838b-7806fb1d4b73 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\">[package]\nname = \"jwt_auth\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https:\/\/doc.rust-lang.org\/cargo\/reference\/manifest.html\n\n[dependencies]\nserde = { version = \"1.0\", features = [\"derive\"] }\nactix-web = \"4\"\nactix-web-httpauth = \"*\"\njwt-simple = \"0.10\"\nrust-crypto = \"0.2\"\nderive_more = \"0.99.17\"\nchrono = \"0.4.31\"\n\n[dependencies.rusqlite]\nversion = \"*\"\nfeatures = [\"bundled\"]\n\n[dependencies.uuid]\nversion = \"1.2.2\"\nfeatures = [\n    \"v4\",\n    \"fast-rng\",\n    \"macro-diagnostics\",\n]<\/pre>\n<p>\u00a0<\/p>\n<h4>API<!-- notionvc: 6fc35f54-b676-47e9-b88f-cfa49ebc5417 --><\/h4>\n<p>\u4eca\u56de\u306eAPI\u306f\u30b7\u30f3\u30d7\u30eb\u306b3\u3064\u3002<\/p>\n<ul>\n<li>JWT \u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u3092\u751f\u6210\u3059\u308bAPI<\/li>\n<li>JWT \u30ea\u30d5\u30ec\u30c3\u30b7\u30e5\u3092\u751f\u6210\u3059\u308bAPI<\/li>\n<li>JWT\u8a8d\u53ef\u306e\u307f\u30a2\u30af\u30bb\u30b9\u53ef\u306eAPI<\/li>\n<\/ul>\n<h5><!-- notionvc: d98f7296-aad7-48c4-9575-916a5d1bfa9a -->\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8<!-- notionvc: c195946e-76fe-4b59-b98a-f488b9827e67 --><\/h5>\n<p>POST \/token\/<\/p>\n<p><code>POST \/token\/refresh<\/code><\/p>\n<p><code>GET \/hello<\/code><\/p>\n<p><!-- notionvc: ebca3c6a-c746-4f46-a7f0-7f910bfa1f74 --><\/p>\n<p>\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u69cb\u6210\u306f\u4ee5\u4e0b\u306e\u901a\u308a\u3002<!-- notionvc: 31984764-ca38-44e6-bb58-91033cbd1f30 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\">jwt_auth\/src\/\n\u251c\u2500\u2500 api\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 mod.rs\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 token.rs\n\u251c\u2500\u2500 constants.rs\n\u251c\u2500\u2500 error.rs\n\u251c\u2500\u2500 main.rs\n\u251c\u2500\u2500 model\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 mod.rs\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 token.rs\n\u2514\u2500\u2500 utils\n    \u251c\u2500\u2500 mod.rs\n    \u2514\u2500\u2500 token.rs<\/pre>\n<p>main.rs\u306b\u306f\u3001API\u306e\u51e6\u7406\u3092\u884c\u3046\u300ccreate_token\u300d\u300crefresh_token\u300d\u300chello\u300d\u30e1\u30bd\u30c3\u30c9\u3092\u7528\u610f\u3002<!-- notionvc: 294f92f7-a2c7-44aa-9e81-d81bdf8b52c2 --><\/p>\n<p>src\/main.rs<!-- notionvc: b56af9b9-96dc-40e3-b120-0c74f1da1195 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">#[actix_web::main]\nasync fn main() -&gt; std::io::Result&lt;()&gt; {\n    HttpServer::new(|| {\n        App::new()\n            .service(\n                web::scope(\"\/token\")\n                    .service(create_token)\n                    .service(refresh_token),\n            )\n            .service(hello)\n    })\n    .bind((\"127.0.0.1\", 8080))?\n    .run()\n    .await\n}<\/pre>\n<h4>create_token<!-- notionvc: 75332fe6-e358-4964-92ab-b7f0e43b9d17 --><\/h4>\n<p>\u307e\u305a\u306f\u3001\u300ccreate_token\u300d\u30e1\u30bd\u30c3\u30c9\u304b\u3089\u3002<\/p>\n<p>\u901a\u5e38\u306f\u3001username\u3068password\u3092\u30ea\u30af\u30a8\u30b9\u30c8\u3067\u53d7\u3051\u3001\u51e6\u7406\u3092\u884c\u3046\u306e\u3067\u3059\u304c\u3001\u4eca\u56de\u306f\u7c21\u6613\u306a\u8a8d\u8a3c\u3068\u3044\u3046\u3053\u3068\u3067\u3001username\u3068password\u306f\u56fa\u5b9a\u3067\u53d6\u308a\u6562\u3048\u305a\u3001\u30ea\u30af\u30a8\u30b9\u30c8\u304c\u6765\u308b\u3068\u3059\u3079\u3066\u901a\u904e\u3059\u308b\u3088\u3046\u306b\u3057\u3066\u304a\u304d\u307e\u3059\u3002<\/p>\n<p>src\/api\/token.rs<\/p>\n<p><!-- notionvc: b6b43dcb-cd54-4ab1-bf83-18de10751d31 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">#[post(\"\/\")]\nasync fn create_token(data: web::Json&lt;CreateTokenRequest&gt;) -&gt; Result&lt;HttpResponse, ServiceError&gt; {\n    if !(data.username == \"daisuke\" &amp;&amp; data.password == \"1234\") {<\/pre>\n<p>username\u3068password\u306e\u8a8d\u8a3c\u304c\u901a\u904e\u3067\u304d\u308b\u3068\u3001\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u3068\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5\u30c8\u30fc\u30af\u30f3\u3092\u767a\u884c\u3057\u307e\u3059\u3002create_access_token\u30e1\u30bd\u30c3\u30c9\u3068\u3001create_refresh_token\u30e1\u30bd\u30c3\u30c9\u306fsrc\/utils\u306b\u5b9a\u7fa9<span class=\"notion-enable-hover\" data-token-index=\"1\">\u3002<\/span><!-- notionvc: a223cc2f-0c0d-4183-ba1f-fd76351aa1bb --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">let token = create_access_token()?;\nlet refresh = create_refresh_token()?;\n\nOk(HttpResponse::Ok().json(CreateTokenResponse {\n    token,\n    refresh_token: refresh,\n}))<\/pre>\n<p>create_custom_claims\u30e1\u30bd\u30c3\u30c9\u3067claim\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/p>\n<p>\u4eca\u56de\u306f\u3001\u6709\u52b9\u671f\u9650\u3092\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u306f15\u5206\u9593\u3001\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5\u30c8\u30fc\u30af\u30f3\u306b\u306f24\u6642\u9593\u306b\u8a2d\u5b9a\u3057\u3066\u304a\u304d\u307e\u3059\u3002\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u306e\u6709\u52b9\u671f\u9650\u304c\u5207\u308c\u308b\u3068\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5\u30c8\u30fc\u30af\u30f3\u3092\u7528\u3044\u3066\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u3092\u66f4\u65b0\u3059\u308b\u30d5\u30ed\u30fc\u3068\u306a\u308a\u307e\u3059\u3002<\/p>\n<p><!-- notionvc: d56b40c0-cd3d-448b-8615-e407d3b9abec -->utils\/token.rs<!-- notionvc: 0ad7f1b0-ab29-46e7-8f11-ad5db20e38e9 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">pub fn create_access_token() -&gt; Result&lt;String, ServiceError&gt; {\n    let claims = create_custom_claims(false, Duration::from_mins(15));\n    claims_authenticate(claims)\n}\n\npub fn create_refresh_token() -&gt; Result&lt;String, ServiceError&gt; {\n    let claims = create_custom_claims(true, Duration::from_hours(24));\n    claims_authenticate(claims)\n}<\/pre>\n<p>\u00a0<\/p>\n<h4>create_custom_claims\u3001claims_authenticate<!-- notionvc: 1832f5bd-e00b-4a02-9894-77db4796b9bf --><\/h4>\n<p>jwt-simple\u30af\u30ec\u30fc\u30c8\u3092\u7528\u3044\u3066\u72ec\u81ea\u306eClaims\u3092\u4f5c\u6210\u3057\u3001JWT\u3092\u4f5c\u6210\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n<p>\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u306eis_refresh\u30d5\u30e9\u30b0\u306ffalse\u3001\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5\u30c8\u30fc\u30af\u30f3\u306eis_refresh\u30d5\u30e9\u30b0\u306ftrue\u3092\u53d7\u53d6\u3001\u305d\u308c\u305e\u308c\u306e\u6709\u52b9\u671f\u9650\u3092\u53d7\u53d6\u308a\u3001is_refresh\u30d5\u30e9\u30b0\u3092\u542b\u3081\u305f\u30ab\u30b9\u30bf\u30e0\u306aclaims\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/p>\n<p><!-- notionvc: 2e620400-52a2-4afd-9a7c-51b21db0d7b5 -->create_custom_claims\u30e1\u30bd\u30c3\u30c9<!-- notionvc: d36cd736-c883-4feb-a98b-269be0156bee --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">fn create_custom_claims(is_refresh: bool, duration: Duration) -&gt; JWTClaims&lt;TokenClaims&gt; {\n    Claims::with_custom_claims(\n        TokenClaims {\n            refresh: is_refresh,\n        },\n        duration,\n    )\n    .with_subject(1)\n    .with_jwt_id(Uuid::new_v4().to_string())\n}<\/pre>\n<p>\u30ab\u30b9\u30bf\u30e0claims\u3092\u542b\u3081\u305fpayload\u3092\u5143\u306bJWT\u306e\u751f\u6210\u3092\u884c\u3063\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n<p>create_token_key()\u3067\u3001 JWT\u306eSignature\u3092\u751f\u6210\u3057\u3001claims_authenticate\u30e1\u30bd\u30c3\u30c9\u306b\u3066\u3001claims\u3092\u5f15\u6570\u3067\u6e21\u3057JWT\u3092\u4f5c\u6210\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n<p><!-- notionvc: b1798f82-1fb6-4532-8b87-6235a2c9c8ec -->claims_authenticate\u30e1\u30bd\u30c3\u30c9<!-- notionvc: db14d833-3b0c-4408-b717-98271c59f67e --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">fn claims_authenticate(claims: JWTClaims&lt;TokenClaims&gt;) -&gt; Result&lt;String, ServiceError&gt; {\n    if let Ok(token) = create_token_key().authenticate(claims) {\n        Ok(token)\n    } else {\n        Err(ServiceError::InternalServerError {\n            error_message: MESSAGE_PROCESS_TOKEN_ERROR.to_string(),\n        })\n    }\n}<\/pre>\n<p>create_token_key\u30e1\u30bd\u30c3\u30c9\u3067\u3001\u79d8\u5bc6\u9375\u3092\u5143\u306b jwt-simple\u30af\u30ec\u30fc\u30c8\u306eHS256\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0\u3092\u7528\u3044\u3066\u3001Signature\u3092\u751f\u6210\u3057\u307e\u3059**\u3002**\u300c&#8221;your_secret_key&#8221;\u300d\u304c\u72ec\u81ea\u3067\u8a2d\u5b9a\u3059\u308b\u79d8\u5bc6\u9375\u3068\u306a\u308a\u3001\u3053\u3061\u3089\u304c\u6f0f\u308c\u3066\u3057\u307e\u3063\u305f\u308a\u3059\u308b\u3068\u3001\u30c8\u30fc\u30af\u30f3\u306e\u4e0d\u6b63\u751f\u6210\u306a\u3069\u304c\u3067\u304d\u3066\u3057\u307e\u3046\u306e\u3067\u3001\u5916\u90e8\u306b\u6f0f\u308c\u306a\u3044\u3088\u3046\u306b\u6ce8\u610f\u304c\u5fc5\u8981\u3068\u306a\u308a\u307e\u3059\u3002<\/p>\n<p>\u4eca\u56de\u306f\u7c21\u6613\u306a\u306e\u3067\u300c&#8221;your_secret_key&#8221;\u300d\u306e\u56fa\u5b9a\u6587\u5b57\u5217\u3067\u751f\u6210\u3002<\/p>\n<p><!-- notionvc: 7859d837-f906-4a01-b6b3-002ba1dbf017 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">fn create_token_key() -&gt; HS256Key {\n    HS256Key::from_bytes(b\"your_secret_key\")\n}<\/pre>\n<p>\u3068\u3044\u3063\u305f\u6d41\u308c\u3067\u3001\u30d8\u30c3\u30c0\u30fc\uff08Header\uff09\u3001\u30da\u30a4\u30ed\u30fc\u30c9\uff08Payload\uff09\u3001\u7f72\u540d\uff08Signature\uff09\u3001\u3092\u542b\u3093\u3060JWT\uff08JSON Web Token\uff09\u306e\u751f\u6210\u304c\u884c\u3048\u307e\u3057\u305f\u3002<\/p>\n<p>\u751f\u6210\u3057\u305f\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\uff08token\uff09\u3068\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5\u30c8\u30fc\u30af\u30f3\uff08refresh_token\uff09\u3092\u3001\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u306bJSON\u3067\u8fd4\u5374\u3057\u307e\u3059\u3002\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u5074\u306f\u3053\u3061\u3089\u3092\u7528\u3044\u3066\u8a8d\u53efAPI\u306b\u30a2\u30af\u30bb\u30b9\u3057\u307e\u3059\u3002<\/p>\n<p><!-- notionvc: 9fd96f8e-c7f2-4509-ad01-7987cb1d2b6d --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\">{\n  \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MDY4NDEwODUsImV4cCI6MTcwNjg0MTE0NSwibmJmIjoxNzA2ODQxMDg1LCJzdWIiOiIxIiwianRpIjoiOGNhZDk2MmItYWVhYy00MmMzLWFjNTgtOGYwNTdkODg0YmQzIiwicmVmcmVzaCI6ZmFsc2V9.mm1hUxevMWoWaNhSCfzKEmry6117Fc355AMxnSZ6E6A\",\n  \"refresh_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MDY4NDEwODUsImV4cCI6MTcwNjkyNzQ4NSwibmJmIjoxNzA2ODQxMDg1LCJzdWIiOiIxIiwianRpIjoiZWMxMmRhZTItZWE1Ni00NGZjLWI3ZmQtNTk4NDkyMjc3YmExIiwicmVmcmVzaCI6dHJ1ZX0.OLyYaST_mkIMbZYUU6-QCfT6dYT3URmoUERGQJ5Kwl4\"\n}<\/pre>\n<h4>hello<!-- notionvc: cd06cd8f-b66b-44b3-b631-e4ffd3955336 --><\/h4>\n<p>hello\u306eAPI\u306f\u3001JWT\u8a8d\u53ef\u3055\u308c\u305fAPI\u3068\u306a\u308b\u306e\u3067\u3001HttpRequest\u306eheader\u30bb\u30af\u30b7\u30e7\u30f3\u306b\u751f\u6210\u3055\u308c\u305fJWT\u3092\u4ed8\u4e0e\u3057\u3066\u30ea\u30af\u30a8\u30b9\u30c8\u3059\u308b\u5f62\u3068\u306a\u308a\u307e\u3059\u3002<\/p>\n<p>\u5148\u7a0b\u751f\u6210\u3055\u308c\u305f\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u3092\u7528\u3044\u3066\u3001header\u30bb\u30af\u30b7\u30e7\u30f3\u306eAuthorization\u306b\u4ed8\u4e0e\u3057\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u884c\u3044\u307e\u3059\u3002<\/p>\n<p><!-- notionvc: aaf4d85e-dd88-43fb-b98e-535c1445f1cd --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\">Authorization [JWT token]<\/pre>\n<p>\u300c [JWT token]\u300d\u306f\u3001Bearer\u306e\u6587\u5b57\u5217\u3001\u534a\u89d2\u30b9\u30da\u30fc\u30b9\u306e\u5f8c\u306b\u751f\u6210\u3055\u308c\u305f\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u3092\u3092\u3075\u3088\u3057\u307e\u3059\u3002<!-- notionvc: 1fd3415b-b044-43b9-afcb-4449fba5282f --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\">Bearer eyJhbGciOiJIUzI1NiIs...<\/pre>\n<p>hello\u30e1\u30bd\u30c3\u30c9\u306f\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u3092\u691c\u8a3c\u3057\u3001\u554f\u984c\u306a\u3051\u308c\u3070\u300c&#8221;Authorized Access Success! Hello World!&#8221;)\u300d\u306e\u6587\u5b57\u5217\u3092\u8fd4\u5374\u3059\u308b\u6d41\u308c\u3068\u306a\u308a\u307e\u3059\u3002<!-- notionvc: fb88242a-d539-4f8a-a1ea-e26d5baf6665 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">#[get(\"\/hello\")]\nasync fn hello(req: HttpRequest) -&gt; Result&lt;HttpResponse, ServiceError&gt; {\n    let token = get_token(req)?;\n    let claims = claims_verify_token(&amp;token)?;\n    if claims.custom.refresh {\n        return Err(ServiceError::BadRequest {\n            error_message: MESSAGE_REFRESH_TOKEN_ERROR.to_string(),\n        });\n    }\n    Ok(HttpResponse::Ok().body(\"Authorized Access Success! Hello World!\"))\n}<\/pre>\n<p>\u307e\u305a\u306f\u3001get_token\u3067HttpRequest\u306eheader\u30bb\u30af\u30b7\u30e7\u30f3\u306e<span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"1\">Authorization<\/span>\u306b\u4ed8\u4e0e\u3055\u308c\u305fJWT\u3092\u53d6\u308a\u51fa\u3057\u307e\u3059\u3002<span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"3\">Authorization<\/span> \u306eValue\u3088\u308a\u3001\u300cBearer\u300d\u307e\u305f\u306f\u300cbearer\u300d\u3092\u5224\u5b9a\u3001\u305d\u3061\u3089\u306e\u6587\u5b57\u5217\u3000\u3092trim\u3057\u3001\u30c8\u30fc\u30af\u30f3\u3092\u53d6\u308a\u51fa\u3057\u307e\u3059\u3002<!-- notionvc: 10376208-f215-4f69-9051-2bce5996a381 --><\/p>\n<p>utils\/token.rs<!-- notionvc: 07a3c28e-b78a-4965-be1e-ae0085990831 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">pub fn get_token(req: HttpRequest) -&gt; Result&lt;String, ServiceError&gt; {\n    if let Some(auth_header) = req.headers().get(AUTHORIZATION) {\n        if let Ok(auth_str) = auth_header.to_str() {\n            if is_auth_header_valid(auth_header) {\n                let token = auth_str[6..auth_str.len()].trim();\n                return Ok(token.to_string());\n            }\n        }\n    }\n    Err(ServiceError::InternalServerError {\n        error_message: MESSAGE_PROCESS_TOKEN_ERROR.to_string(),\n    })\n}<\/pre>\n<p>is_auth_header_valid\u30e1\u30bd\u30c3\u30c9<!-- notionvc: d58c1180-6ac4-45e1-a844-1e4318623429 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">pub fn is_auth_header_valid(auth_header: &amp;HeaderValue) -&gt; bool {\n    if let Ok(auth_str) = auth_header.to_str() {\n        return auth_str.starts_with(\"bearer\") || auth_str.starts_with(\"Bearer\");\n    }\n    false\n}<\/pre>\n<p>claims_verify_token\u30e1\u30bd\u30c3\u30c9\u3067\u30ea\u30af\u30a8\u30b9\u30c8\u3055\u308c\u305f\u30c8\u30fc\u30af\u30f3\u3092\u691c\u8a3c\u3057\u307e\u3059\u3002<\/p>\n<p>create_token_key\u30e1\u30bd\u30c3\u30c9\u306f\u5148\u7a0b\u306e\u30c8\u30fc\u30af\u30f3\u751f\u6210\u3067\u3082\u7528\u3044\u305f\u30e1\u30bd\u30c3\u30c9\u3068\u306a\u308a\u307e\u3059\u306e\u3067\u3001\u3053\u3053\u3067Signat\u3053\u3053\u304c\u7570\u306a\u308b\u3068\u8a8d\u53ef\u30a8\u30e9\u30fc\u3068\u306a\u308b\u5f62\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<p>claims_verify_token<\/p>\n<p><!-- notionvc: e2f4ff48-e8f6-4214-9e28-bb2a915c2c8d --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">pub fn claims_verify_token(token: &amp;str) -&gt; Result&lt;JWTClaims&lt;TokenClaims&gt;, ServiceError&gt; {\n    if let Ok(claims) = create_token_key().verify_token::&lt;TokenClaims&gt;(token, None) {\n        Ok(claims)\n    } else {\n        Err(ServiceError::Unauthorized {\n            error_message: MESSAGE_TOKEN_MISSING.to_string(),\n        })\n    }\n}<\/pre>\n<h4>refresh<!-- notionvc: fe44afd6-dabd-4bc2-a2de-f3c483ec3cfe --><\/h4>\n<p>\u6700\u5f8c\u306f\u3001\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5\u30c8\u30fc\u30af\u30f3\u3092\u751f\u6210\u3059\u308b\u6d41\u308c\u3068\u306a\u308a\u307e\u3059\u3002\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u306f15\u5206\u306e\u6709\u52b9\u671f\u9650\u3057\u304b\u306a\u3044\u305f\u3081\u3001\u6709\u52b9\u671f\u9650\u304c\u5207\u308c\u305f\u5834\u5408\u3001\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5\u30c8\u30fc\u30af\u30f3\u3092\u7528\u3044\u3066\u65b0\u305f\u306b\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u3092\u751f\u6210\u3057\u307e\u3059\u3002<\/p>\n<p>\u5148\u7a0b\u306ehelloAPI\u3068\u307b\u307c\u540c\u3058\u3067\u3059\u304c\u3001\u7570\u306a\u308b\u70b9\u306fpayload\u306eclaims\u306b\u8a2d\u5b9a\u3057\u305f\u300crefresh\u300d\u304cTrue\u304b\u3069\u3046\u304b\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<p><!-- notionvc: eaa9af7d-184c-4d90-9f27-51725b41d013 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">#[post(\"\/refresh\")]\nasync fn refresh_token(req: HttpRequest) -&gt; Result&lt;HttpResponse, ServiceError&gt; {\n    let request_token = get_token(req)?;\n    let claims = claims_verify_token(&amp;request_token)?;\n    if !claims.custom.refresh {\n        return Err(ServiceError::BadRequest {\n            error_message: MESSAGE_REFRESH_TOKEN_ERROR.to_string(),\n        });\n    }\n    let token = create_access_token()?;\n\n    Ok(HttpResponse::Ok().json(CreateRefreshTokenResponse { token }))\n}<\/pre>\n<p>refresh\u30c8\u30fc\u30af\u30f3\u306e\u5834\u5408\u306f\u3001refresh\u304ctrue\u3002<!-- notionvc: 678d413b-b6b9-46ef-b763-d87ee6384792 --><\/p>\n<p>\u00a0<\/p>\n<p><span class=\"notion-enable-hover\" data-token-index=\"0\">refresh\u30c8\u30fc\u30af\u30f3\u306epayload<\/span><!-- notionvc: e6e6476f-1dc0-4ce1-a0ad-284e8961ad09 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\">{\n  \"iat\": 1706841085,\n  \"exp\": 1706841145,\n  \"nbf\": 1706841085,\n  \"sub\": \"1\",\n  \"jti\": \"8cad962b-aeac-42c3-ac58-8f057d884bd3\",\n  \"refresh\": true\n}<\/pre>\n<p>refresh\u30c8\u30fc\u30af\u30f3\u3067\u306f\u306a\u3044\u5834\u5408\u306f\u3001\u30a8\u30e9\u30fc\u3092\u8fd4\u5374\u3002<!-- notionvc: 7357a8c4-608c-43f4-95d0-720b5d46b92c --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">if !claims.custom.refresh {<\/pre>\n<p>refresh\u30c8\u30fc\u30af\u30f3\u3092\u691c\u8a3c\u3057\u3001\u554f\u984c\u306a\u3051\u308c\u3070\u3001\u6700\u521d\u306b\u3082\u5b9f\u884c\u3057\u305fcreate_access_token\u3067\u518d\u3073\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u3092\u751f\u6210\u3057\u307e\u3059\u3002<!-- notionvc: a517dc3f-e23c-4073-aa97-00e816b84001 --><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">pub fn create_access_token() -&gt; Result&lt;String, ServiceError&gt; {\n    let claims = create_custom_claims(false, Duration::from_mins(15));\n    claims_authenticate(claims)\n}<\/pre>\n<p>\u6210\u529f\u3059\u308b\u3068\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u304c\u8fd4\u5374\u3055\u308c\u307e\u3059\u306e\u3067\u3001\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u5074\u3067\u66f4\u65b0\u51e6\u7406\u3092\u884c\u3048\u3070\u518d\u3073\u8a8d\u53ef\u30ea\u30af\u30a8\u30b9\u30c8\u304c\u884c\u3046\u5f62\u3068\u306a\u308a\u307e\u3059\u3002<\/p>\n<p>\u3068\u3044\u3063\u305f\u5f62\u3067\u3056\u3063\u304f\u308a\u8aac\u660e\u3067\u7533\u3057\u8a33\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u304c\u3001\u7c21\u6613\u306eJWT\u8a8d\u8a3c\u8a8d\u53ef\u306eAPI\u304c\u4f5c\u6210\u3067\u304d\u307e\u3057\u305f\u3002<\/p>\n<p>\u6b21\u56de\u306f\u3001MongoDB\u3092\u7528\u3044\u3066\u767b\u9332\u3055\u308c\u305f\u30e6\u30fc\u30b6\u30fc\u3067\u306e\u8a8d\u8a3c\u8a8d\u53efAPI\u4f5c\u6210\u3092\u884c\u3063\u3066\u884c\u304d\u305f\u3044\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n<p>\u3067\u306f\u3067\u306f\u3041\u3002<\/p>\n<p><!-- notionvc: bc6fb964-a652-477c-8f1c-72e872be474c --><\/p>\n<p>\u00a0<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u3069\u3082\u3067\u3059\u3002 \u3044\u3084\u3041\u3001\u3082\u30462\u6708\u3082\u7d42\u308f\u308b\u3068\u3044\u3046\u3053\u3068\u3067\u3001\u672c\u5f53\u306b\u6642\u9593\u306e\u6d41\u308c\u3092\u65e9\u304f\u611f\u3058\u3066\u304a\u308a\u307e\u3059\u3002 \u696d\u52d9\u3067\u306fRust\u3067\u30bd\u30d5\u30c8\u30a6\u30a7\u30a2\u3092\u4f5c\u6210\u3057\u3066\u304a\u308a\u307e\u3059\u304c\u3001\u8da3\u5473\u3067\u306fRust\u3067\u30b5\u30fc\u30d0\u30fc\u958b\u767a\u3082\u884c\u3063\u3066\u3044\u307e\u3057\u3066\u3001\u4eca\u56de\u3082\u524d\u56de\u306b\u5f15\u304d\u7d9a\u304dRust\u306e [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":11750,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[299],"tags":[331,330,176,166,47,335,327,45,78,118],"class_list":["post-11748","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-rust","tag-actix-web-2","tag-actix-web","tag-html5","tag-iphone","tag-javascript-2","tag-jwt","tag-rust","tag-web","tag-78","tag-118"],"_links":{"self":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts\/11748","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=11748"}],"version-history":[{"count":2,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts\/11748\/revisions"}],"predecessor-version":[{"id":11751,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts\/11748\/revisions\/11751"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/media\/11750"}],"wp:attachment":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=11748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=11748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=11748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}