Upgrade to Pro — share decks privately, control downloads, hide ads and more …

estie、Rustで新プロダクト作るってよ - 2022/2/16

estie、Rustで新プロダクト作るってよ - 2022/2/16

2022/2/16に開催されたイベントで使用した資料です。
https://seriesa.estie.jp/event_rust

# イベント概要
estie(エスティ)は2022年1月12日、約10億円のシリーズA資金調達を発表いたしました。調達した資金を活用して、商業用不動産業界のデジタルトランスフォーメーションをより加速すべく、主力サービスである「estie pro」を拡張するマルチプロダクト戦略のもと、新しいプロダクトをどんどん開発しています。
そのうちの1つは、最近注目があつまるRustをバックエンドに採用したWebアプリです。どのようにRustを活用してWebアプリを開発するのか、新しい言語としてRustを採用したestieでの例をご紹介します!

# 企業ページ
https://www.estie.jp/corp/

# エンジニア採用情報
https://aspiring-step-dba.notion.site/estie-ba5b74c80e39475ebc8c3f15f879e776

5d9c07f0c2044b1407a84d88362bc84d?s=128

estie | エスティ

February 16, 2022
Tweet

More Decks by estie | エスティ

Other Decks in Programming

Transcript

  1. None
  2.  ొஃऀ঺հ ࢘ձ

  3.  ຊ೔ͷྲྀΕ  Φʔϓχϯά r FTUJFͱ͸ʁ <NJO>  LFOLPPPP ʰ3VTUͰ΢ΣϒΞϓϦʱ<NJO

    NJO2">  ฏా౦ເʰ3VTUº/FYUKTº"VUIͰϢʔβʔೝূʱ<NJO NJO2">  શମΛ௨ͯ͠ͷ࣭ٙɾΫϩʔδϯά <NJO> )BTIUBHFTUJF@ST 2"ػೳΛͥͻ͝׆༻͍ͩ͘͞ʂ
  4.  FTUJFͱ͸ʁ

  5. 

  6. ৽ίʔϙϨʔταΠτ ʢ IUUQTXXXFTUJFKQDPSQ ʣ ͷ͝঺հ

  7. ͜Ε·ͰͷϓϩμΫτ܈

  8. ͦΕΛࢧ͑ΔਐԽ͠ଓ͚ΔσʔλύΠϓϥΠϯ

  9. 20/4 20/5 20/6 20/7 20/8 20/9 20/10 20/11 20/12 21/1

    21/2 21/3 21/4 21/5 21/6 21/7 21/8 21/9 21/10 21/11  ϏδωεΠϯύΫτ ओͳಋೖاۀ ԻॱɺҰ෦ൈਮ BOENPSF .33 Y ௚ۙϲ݄
  10.  1IBTF ۭࣨɾاۀ৘ใͷ σʔλج൫ߏங 1IBTF 1IBTF τϥϯβΫγϣϯ ϓϥοτϑΥʔϜ

  11.  ෳ਺ϓϩμΫτͷ૬৐ޮՌͰاۀՁ஋ΛരൃతʹߴΊΔ 1SPEVDU ۭࣨɾاۀ৘ใͷ σʔλج൫ߏங 1SPEVDU 1SPEVDU τϥϯβΫγϣϯ ϓϥοτϑΥʔϜ "1*ߏ૝

    ଟ༷ͳݴޠ ৽͍͠ϓϩμΫτͷ͕ͭόοΫΤϯυΛ3VTUͰॻ͍ͯ·͢ʂ ʢࢣఋ੍౓Λ੔͑࢝Ί͍ͯ·͢ʣ
  12.  ͬͦ͘͞-5͍͖·͠ΐ͏ʂ

  13. 3VTUͰ΢ΣϒΞϓϦ ΞϧόΠτʢਂ໷ɾٳ೔γϑτʣ LFOLPPPP

  14. 3VTUͱ͸

  15.  3VTUͷಛ௕  $ ฒʹ଎͍  ΋ͱ΋ͱ'JSFGPY༻ݴޠ  -JOVYΧʔωϧʹ࢖ΘΕͦ͏ 

    "84Ͱ͸7.΍04ͳͲʹ࢖ΘΕ͍ͯΔ  ίϯύΠϥ͕Ϧιʔε؅ཧʹ͍ͭͯνΣοΫ͠·͘Δ
  16.  Ͱ΋ɺ೉͍͠ΜͰ͠ΐ͏ʜʁ

  17.  3VTU͕೉͍͠ͱ͍͏ӟ  ίϯύΠϥͷνΣοΫ͕ݫ͗ͯ͢͠Ұੜ௨Βͳ͍ʜ  ॴ༗ݖʁ஌Βͳ͍֓೦͕ͨ͘͞Μग़ͯ͘Δʜ

  18.  ͦ΋ͦ΋ϓϩάϥϛϯά͕೉͍͠ʂʂʂ

  19.  void listOperation(List<String> list) { list.add("Awesome!"); } Javaではよく⾒る関数だが…

  20.  void listOperation(List<String> list) { list.add("Awesome!"); } Javaではよく⾒る関数だが… • 実は

    List がミュータブルであることを強制 • ImmutableList を渡すと Runtime Exception • 呼び出し元でも予期しないかも?
  21.  void listOperation(List<String> list) { list.add("Awesome!"); } Javaではよく⾒る関数だが… • 実は

    List がミュータブルであることを強制 • ImmutableList を渡すと Runtime Exception • 呼び出し元でも予期しないかも? →コメントをつける・関数名を⼯夫するしかない
  22.  fn list_operation(list: Vec<String>) {…} • 呼び出し元では list は使われない •

    move しているので fn list_operation(list: &Vec<String>) {…} • イミュータブルな参照 fn list_operation(list: &mut Vec<String>) {…} • ミュータブルな参照
  23.  ϓϩάϥϛϯά͸೉͍͠ʜ  ͦ΋ͦ΋ϓϩάϥϛϯά͸೉͍͠ʜ  ϓϩάϥϛϯάͷ೉͍͠ϙΠϯτΛਓྗͰνΣοΫ͢Δͷ͸େมʜ  ฒྻϓϩάϥϛϯά͸ਓྨʹ͸ෆՄೳ  3VTUʹ೉͍͠ϙΠϯτΛԡ͚ͭ͠Α͏ʂ

  24.  -JOVY࡞Βͳ͍ͷͰʜ

  25.   3VTU͸௿ϨΠϠʔઐ༻ݴޠͰ͸ͳ͍ʂ  ศརͳݴޠػೳ͕͋Δ ݸਓతͳΠνΦγ͸ USBJU  $BSHPͱ͍͏ඪ४ͷύοέʔδ؅ཧπʔϧ͕͋Δ 

    ීஈͷϓϩάϥϛϯάݴޠͱͯ͠Φεεϝ
  26. 3VTUͰ΢Σϒ։ൃ

  27.  3VTUΛऔΓר͘΢Σϒ։ൃࣄ৘  ೥൒લʹඇಉظߏจ BTZODBXBJU͕҆ఆԽ  ͦΕҎલ΋ඇಉظॲཧ͸ग़དྷ͕ͨɺ؆୯ʹॻ͚ΔΑ͏ʹͳͬͨ  ೥͔͚ͯϥΠϒϥϦɾϑϨʔϜϫʔΫ͕ॆ࣮ 

    ݹࢀϥΠϒϥϦ͕ BTZODBXBJUରԠ  ॻ͖΍͔͢͞Β৽͍͠ϥΠϒϥϦ΋ଓʑ
  28.  3VTUͰ΢ΣϒΞϓϦ • ΢ΣϒϑϨʔϜϫʔΫBDUJYXFC • +BWBͷ 4QSJOHɺ1ZUIPOͷ 'MBTL • 42-υϥΠόʔTRMY

    • .Z42-Ͱ࢖༻ • 03.Ͱ͸ͳ͘ɺΫΤϦ௚ॻ͖ • 4ΫϥΠΞϯτSVTPUP • ݹࢀ "84ϥΠϒϥϦ
  29.  #[post("/api/buildings")] pub async fn create_building( request: Json<CreateBuildingRequest>, pool: Data<MySqlPool>,

    auth0_id: ReqData<Auth0Id>, ) -> Result<HttpResponse> { let building = Building::from(request.building); verify_user(&pool, &auth0_id.0).await?; let id = Building::insert(&pool, &building).await?; Ok(Json(CreateBuildingResponse { building_id: id })) }
  30.  #[post("/api/buildings")] pub async fn create_building( request: Json<CreateBuildingRequest>, pool: Data<MySqlPool>,

    auth0_id: ReqData<Auth0Id>, ) -> Result<HttpResponse> { let building = Building::from(request.building); verify_user(&pool, &auth0_id.0).await?; let id = Building::insert(&pool, &building).await?; Ok(Json(CreateBuildingResponse { building_id: id })) } JSONとして受け取るように指定 FWでパース等やってもらう
  31.  #[post("/api/buildings")] pub async fn create_building( request: Json<CreateBuildingRequest>, pool: Data<MySqlPool>,

    auth0_id: ReqData<Auth0Id>, ) -> Result<HttpResponse> { let building = Building::from(request.building); verify_user(&pool, &auth0_id.0).await?; let id = Building::insert(&pool, &building).await?; Ok(Json(CreateBuildingResponse { building_id: id })) } FWからSQLコネクションプールを もらってくる
  32.  #[post("/api/buildings")] pub async fn create_building( request: Json<CreateBuildingRequest>, pool: Data<MySqlPool>,

    auth0_id: ReqData<Auth0Id>, ) -> Result<HttpResponse> { let building = Building::from(request.building); verify_user(&pool, &auth0_id.0).await?; let id = Building::insert(&pool, &building).await?; Ok(Json(CreateBuildingResponse { building_id: id })) } ヘッダからトークンを取り出して IDを取得しておいてもらう
  33.  #[post("/api/buildings")] pub async fn create_building( request: Json<CreateBuildingRequest>, pool: Data<MySqlPool>,

    auth0_id: ReqData<Auth0Id>, ) -> Result<HttpResponse> { let building = Building::from(request.building); verify_user(&pool, &auth0_id.0).await?; let id = Building::insert(&pool, &building).await?; Ok(Json(CreateBuildingResponse { building_id: id })) } 返り値は Result
  34.  #[post("/api/buildings")] pub async fn create_building( request: Json<CreateBuildingRequest>, pool: Data<MySqlPool>,

    auth0_id: ReqData<Auth0Id>, ) -> Result<HttpResponse> { let building = Building::from(request.building); verify_user(&pool, &auth0_id.0).await?; let id = Building::insert(&pool, &building).await?; Ok(Json(CreateBuildingResponse { building_id: id })) }
  35. 

  36.  let id = Building::insert(&pool, &building).await?;

  37.  let id = Building::insert(&pool, &building).await?;

  38.  3VTUʹ͓͚Δ    3FTVMUܕͷ FBSMZSFUVSO value, err :=

    f() if err != nil { return nil, err } let value = f()?;
  39.  #[post("/api/buildings")] pub async fn create_building( request: Json<CreateBuildingRequest>, pool: Data<MySqlPool>,

    auth0_id: ReqData<Auth0Id>, ) -> Result<HttpResponse> { let building = Building::from(request.building); verify_user(&pool, &auth0_id.0).await?; let id = Building::insert(&pool, &building).await?; Ok(Json(CreateBuildingResponse { building_id: id })) } マクロで⾊々⽣成してもらう
  40.  BDUJYXFC·ͱΊ • ΄͔ͷݴޠͱಉ͘͡Βָ͍ʹ "1*͕ॻ͚Δ • ඇಉظॲཧ͸ BTZODBXBJU • ΤϥʔϋϯυϦϯά͸

    3FTVMUͱ  
  41. TRMYͱ 3VTUϚΫϩ

  42.  3VTUͷ42-؀ڥ • %JFTFMͱ͍͏ݹࢀ03. • ඇಉظɺඇରԠʜ • ඇಉظରԠͷ 42-ϥΠϒϥϦ TRMY

    • ΫΤϦ௚ॻ͖ • ڧྗͳϚΫϩ
  43.   async fn insert(pool: &MySqlPool, unit: &Unit) -> Result<u64>

    { let unit_id = sqlx::query(r#" INSERT INTO units ( area, floor, building_id ) VALUES (?,?,?)"#, ) .bind(unit.area) .bind(unit.floor) .bind(unit.building_id) .execute(pool) .await? .last_insert_id(); Ok(unit_id) }
  44.   async fn find_by_bid(pool: &MySqlPool, bid: i64) -> Result<Vec<RawUnit>>

    { let units = sqlx::query_as!( RawUnit, "SELECT * FROM units WHERE building_id=?", bid ) .fetch_all(pool) .await?; Ok(units) }
  45.   async fn find_by_bid(pool: &MySqlPool, bid: i64) -> Result<Vec<RawUnit>>

    { let units = sqlx::query_as!( RawUnit, "SELECT * FROM units WHERE building_id=?", bid ) .fetch_all(pool) .await?; Ok(units) }
  46.   sqlx::query_as!( RawUnit, "SELECT * FROM units WHERE building_id=?",

    bid )
  47.   sqlx::query_as!( RawUnit, "SELECT * FROM units WHERE building_id=?",

    bid )
  48.   sqlx::query_as!( RawUnit, "SELECT * FROM units WHERE building_id=?",

    bid ) struct RawUnit { unit_id: i64, area: Decimal, floor: u8, building_id: i64, }
  49.   sqlx::query_as!( RawUnit, "SELECT * FROM units WHERE building_id=?",

    bid ) struct RawUnit { unit_id: i64, area: Decimal, floor: u8, building_id: i64, } もし NULL が含まれていたら……?
  50.   sqlx::query_as!( RawUnit, "SELECT * FROM units WHERE building_id=?",

    bid ) struct RawUnit { unit_id: i64, area: Decimal, floor: u8, building_id: i64, } ↑ このクエリの返り値の型が RawUnit と同じか、 コンパイル時にチェックする。
  51.  42-ΫΤϦͷฦΓ஋ͷܕΛ ίϯύΠϧ࣌ʹνΣοΫ͢Δʙʂʁʂʁ

  52.  3VTUϚΫϩͷେ·͔ͳಈ͖  τʔΫϯྻΛड͚औΔ  ͍Ζ͍Ζॲཧ͢Δ  ͜ͷ෦෼΋3VTUͰॻ͚Δ  ίʔυΛੜ੒͢Δ

  53.   sqlx::query_as!( RawUnit, "SELECT * FROM units WHERE building_id=?",

    bid )
  54.   sqlx::query_as!( RawUnit, "SELECT * FROM units WHERE building_id=?",

    bid ) トークン列
  55.  3VTUϚΫϩͷେ·͔ͳಈ͖  τʔΫϯྻΛड͚औΔ  ͍Ζ͍Ζॲཧ͢Δ  ͜ͷ෦෼΋3VTUͰॻ͚Δ  ίʔυΛੜ੒͢Δ

  56.  3VTUϚΫϩͷେ·͔ͳಈ͖  τʔΫϯྻΛड͚औΔ  ͍Ζ͍Ζॲཧ͢Δ  ͜ͷ෦෼΋3VTUͰॻ͚Δˠ42-ʹ઀ଓͯ͠ɺΫΤϦͷܕΛ֬ೝ  ίʔυΛੜ੒͢Δ

  57. ⼈類 コンパイラ MySQL コード クエリ 型 型チェッ ク

  58.  ·ͱΊɿίϯύΠϧ࣌42-ܕνΣοΫ

  59.  શମͷ·ͱΊ  3VTU͸೉͍͠ʁ ˠ ϓϩάϥϛϯά͕೉͍͠ʂ  3VTU͸௿ϨΠϠʔ޲͚ʁ ˠ ΢Σϒ։ൃ͠Α͏ʂ

     ϚΫϩ͍͢͝ʁ ˠ ͍͢͝Αʜ
  60. 3VTUº/FYUKTº"VUIͰϢʔβʔೝূ  48& 5PNV )JSBUB !UPNV@EFTVZP

  61.   എܠ  "VUIº/FYUKT  "VUIº"DUJY@XFC "HFOEB

  62. • estieはマルチプロダクト化を進めている • それぞれのサービスは将来統合していく想定がある • その際ユーザー情報も統⼀的に管理しきたい എܠ

  63. 個々のサービスそれぞれで認証機能を作りたくはない 全社的な認証基盤を作り始める前にIDaaSの技術検証を進めたい 新規プロダクトでAuth0認証を使うことに എܠ

  64. ϓϩμΫτͷߏ੒ Backend ID Provider BFF Frontend

  65. ೝূϑϩʔ Backend ID Provider BFF Frontend ID Token ID &

    Password セッションCookie JWK ID Token トークンを検証 レスポンス
  66.   എܠ  "VUIº/FYUKT  "VUIº"DUJY@XFC "HFOEB

  67. • クライアント側で認証情報を保持したい • トークンの偽装を難しくしたい ୡ੒͍ͨ͜͠ͱ

  68. ϑϩϯτΤϯυ͔ΒͷϩάΠϯ Backend ID Provider BFF Frontend ID Token ID &

    Password
  69. ϑϩϯτΤϯυ͔ΒͷϩάΠϯ Backend ID Provider BFF Frontend ID Token ID &

    Password セッションCookie
  70. ϑϩϯτΤϯυ͔ΒͷϩάΠϯ Backend ID Provider BFF Frontend ID Token ID &

    Password セッションCookie トークンはサーバーサイド で暗号化・復号化
  71.  *%τʔΫϯΠϯ ペイロード部分の例 +855PLFOͷߏ଄ • ϔομʔ෦ • ॺ໊ݕূ৘ใΛؚΉ • ϖΠϩʔυ෦

    • ΞΧ΢ϯτͷଐੑ৘ใͳͲΛؚΉ • ॺ໊෦ • ೝূࡁΈͰ͋Δ͜ͱΛݕূ͢Δॺ໊ΛؚΉ
  72.  /FYUKTº"VUIΠϯ "VUI3FBDUKT 4%, IUUQTHJUIVCDPNBVUIBVUISFBDU • /FYUKTͰ4UBUJD)5.-&YQPSUΛ࢖༻͍ͯ͠Δ৔߹ • αʔόʔαΠυϨϯμϦϯά࣌ʹϢʔβʔσʔλʹΞΫηε͢Δඞཁ͕ͳ͍৔߹ •

    /FYUKTͷ"1*3PVUFTΛϓϩΩγͱͯ͠࢖༻ͯ͠֎෦"1*Λݺͼग़͢ͷͰ͸ͳ͘ɺΞΫηε τʔΫϯΛऔಘͯ͠ϑϩϯτΤϯυϨΠϠʔ͔Β௚઀֎෦"1*Λݺͼग़͍ͨ͠৔߹ "VUI/FYUKT 4%, IUUQTHJUIVCDPNBVUIOFYUKTBVUI • ͦΕҎ֎ͷ৔߹ • $PPLJFͰͷηογϣϯͷ؅ཧ͕Մೳ
  73.   എܠ  "VUIº/FYUKT  "VUIº"DUJY@XFC "HFOEB

  74. • リクエストしてきているユーザーの認証を⾏いたい • リクエストに付属したトークンの検証を⾏いたい ୡ੒͍ͨ͜͠ͱ

  75. ϑϩϯτΤϯυ͔ΒͷϩάΠϯ Backend ID Provider BFF Frontend ID Token

  76. ϑϩϯτΤϯυ͔ΒͷϩάΠϯ Backend ID Provider BFF Frontend JWKを要求 ID Token

  77. ϑϩϯτΤϯυ͔ΒͷϩάΠϯ Backend ID Provider BFF Frontend JWK JWKを要求 ID Token

  78. ϑϩϯτΤϯυ͔ΒͷϩάΠϯ Backend ID Provider BFF Frontend JWK JWTの検証 JWKを要求 ID

    Token
  79. ϑϩϯτΤϯυ͔ΒͷϩάΠϯ Backend ID Provider BFF Frontend JWK ID Token JWTの検証

    レスポンス JWKを要求
  80.  όοΫΤϯυͰͷϢʔβʔͷೝূΠϯ "DUJY@XFCͷϛυϧ΢ΣΞͰ*%5PLFOΛݕূ͢Δ • "VUIPSJ[BUJPOϔομʔ͔Β+85τʔΫϯΛ֫ಘ • "VUIʹݕূ༻ͷ+8,ΛϦΫΤετ • τʔΫϯΛݕূ

  81. όοΫΤϯυͰͷϢʔβʔͷೝূ pub struct Auth0Middleware<S> { service: Rc<S>, client: Rc<Auth0Client>, }

    impl Auth0Middleware<S> { fn call(&self, req: ServiceRequest) -> Self::Future { let token = parse_bearer_token(&req)?; let auth0_id = match client.get_auth0_id_from_bearer(token); req.extensions_mut().insert(auth0_id); service.call(req).await.map(|res| res.map_into_left_body()) } }
  82. όοΫΤϯυͰͷϢʔβʔͷೝূ pub struct Auth0Middleware<S> { service: Rc<S>, client: Rc<Auth0Client>, }

    impl Auth0Middleware<S> { fn call(&self, req: ServiceRequest) -> Self::Future { let token = parse_bearer_token(&req)?; let auth0_id = match client.get_auth0_id_from_bearer(token); req.extensions_mut().insert(auth0_id); service.call(req).await.map(|res| res.map_into_left_body()) } } HTTPの Authorization HeaderからJWT トークンを抽出
  83. όοΫΤϯυͰͷϢʔβʔͷೝূ pub struct Auth0Middleware<S> { service: Rc<S>, client: Rc<Auth0Client>, }

    impl Auth0Middleware<S> { fn call(&self, req: ServiceRequest) -> Self::Future { let token = parse_bearer_token(&req)?; let auth0_id = match client.get_auth0_id_from_bearer(token); req.extensions_mut().insert(auth0_id); service.call(req).await.map(|res| res.map_into_left_body()) } } JWTトークンを検証 し、auth0のIDを抽 出する
  84. όοΫΤϯυͰͷϢʔβʔͷೝূ fn parse_bearer_token(request: &ServiceRequest) -> Result<&str> { let header =

    request.headers() .get(&actix_web::http::header::AUTHORIZATION)?; let mut parts = header.to_str()?.splitn(2, ' '); let token = parts[1].ok_or_else(|| anyhow::anyhow!("no token"))?; Ok(token) } • BDUJYXFCͷBQJΛ༻͍ͯ"VUIPSJ[BUJPOϔομʔΛநग़ • ϔομʔͷܗࣜ͸ #FBSFSYYYYYYYYYYYYY
  85. όοΫΤϯυͰͷϢʔβʔͷೝূ +85τʔΫϯΛݕূ͢ΔΫϥΠΞϯτ pub struct Auth0Client { client: reqwest::Client, base_url: String,

    } impl Auth0Client { pub(super) async fn get_auth0_id_from_bearer(&self, bearer_token: &str) -> Result<String> { self.validate_jwt_token(bearer_token).await?.sub //JWT payloadのsub } /////ここに⾊々なメソッド }
  86. όοΫΤϯυͰͷϢʔβʔͷೝূ +85τʔΫϯΛݕূ͢ΔҰ࿈ͷॲཧ async fn validate_jwt_token(&self, token: &str) -> Result<JWTPayload> {

    let jwks = self.fetch_jwks().await?; let kid = match decode_header(token)?.kid.unwrap(); let jwk = match jwks.find(&kid) { Some(res) => res, None => return Err(anyhow::anyhow!("Specified key not found in set")), }; Auth0Client::dec_jwt(jwk, token) }
  87. όοΫΤϯυͰͷϢʔβʔͷೝূ +85τʔΫϯΛݕূ͢ΔҰ࿈ͷॲཧ async fn validate_jwt_token(&self, token: &str) -> Result<JWTPayload> {

    let jwks = self.fetch_jwks().await?; let kid = match decode_header(token)?.kid.unwrap(); let jwk = match jwks.find(&kid) { Some(res) => res, None => return Err(anyhow::anyhow!("Specified key not found in set")), }; Auth0Client::dec_jwt(jwk, token) } Auth0に検証⽤の鍵 をリクエスト
  88. +85τʔΫϯΛݕূ͢ΔҰ࿈ͷॲཧ async fn validate_jwt_token(&self, token: &str) -> Result<JWTPayload> { let

    jwks = self.fetch_jwks().await?; let kid = match decode_header(token)?.kid.unwrap(); let jwk = match jwks.find(&kid) { Some(res) => res, None => return Err(anyhow::anyhow!("Specified key not found in set")), }; Auth0Client::dec_jwt(jwk, token) } 署名部を⽤いて トークンを検証 όοΫΤϯυͰͷϢʔβʔͷೝূ
  89. +8,ΛϦΫΤετ͢Δ async fn fetch_jwks(&self) -> Result<Jwks> { let uri =

    format!("{}/.well-known/jwks.json", self.base_url); let res = self.client.get(uri).send().await?; let val = res.json::<Jwks>().await?; Ok(val) } όοΫΤϯυͰͷϢʔβʔͷೝূ
  90. όοΫΤϯυͰͷϢʔβʔͷೝূ +85τʔΫϯΛݕূ͢Δ fn dec_jwt(jwk: &Jwk, jwt: &str) -> Result<JWTPayload> {

    match decode::<JWTPayload>( jwt, &DecodingKey::from_rsa_components(&jwk.n, &jwk.e), &Validation::new(Algorithm::RS256), ) { Ok(c) => Ok(c.claims), e => Err(anyhow::anyhow!("failed to decode jwt: {:?}", e)), } }
  91. όοΫΤϯυͰͷϢʔβʔͷೝূ BQJଆͰBVUI@JEΛ࢖༻͢Δ #[post("/api/buildings")] pub(crate) async fn create_building( request: web::Json<CreateBuildingRequest>, pool:

    web::Data<MySqlPool>, auth0_id: web::ReqData<Auth0Id>, ) -> ApiResult<impl Responder> { let request = request.into_inner(); let building_info = BuildingInfo::try_from(request.building_info).invalid_request()?; verify_user(pool.as_ref(), &auth0_id.0).await?; let building_id = Building::insert(pool.as_ref(), &building_info) .await .log_db_err()?; Ok(web::Json(CreateBuildingResponse { building_id })) }
  92. • Auth0×Actix_web×Next.jsでユーザー認証を⾏った • クライアントがAuth0サーバーから獲得したJWTトーク ンをRustバックエンドで検証してレスポンスを返す ·ͱΊ

  93.  ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠

  94.  ຊ೔͸͝ࢀՃ͍͖ͨͩ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ ڵຯΛ࣋ͨΕͨํ͸ͥͻ IUUQTKPCTFTUJFKQPS!JX@UBUTV ·Ͱʂ