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

jjug ccc 2017 spring ccc_g1

jjug ccc 2017 spring ccc_g1

yuichiro umezawa

May 19, 2017
Tweet

More Decks by yuichiro umezawa

Other Decks in Technology

Transcript

  1. ඇػೳཁ݅ͱ4QSJOH#PPU
    ++6($$$4QSJOH
    DDD@H

    View Slide

  2. ++6($$$4QSJOHDDD@H
    ໨࣍ͱΰʔϧ
    w ໨࣍
    w ࣗݾ঺հ
    w ඇػೳཁ݅ͱ͸
    w 4QSJOH#PPU"DUVBUPS
    w 4QSJOH4FDVSJUZ0UIFST
    w ·ͱΊ
    w ΰʔϧ
    w ඇػೳཁ݅ͷ೉͠͞ͱରԠͷίπΛ஌Δ
    w εʔπͱςοΫͷڮ౉͠

    View Slide

  3. ++6($$$4QSJOHDDD@H
    ࣗݾ঺հ
    w കᖒ༤Ұ࿠ ͏Ί͟ΘΏ͏͍ͪΖ͏

    w ͕Δ͕΂ !HBSCBHFUPXO

    w גࣜձࣾ%54
    w 4*FS
    w ೥݄ೖࣾ
    w ೥݄ҟಈ
    w डୗ։ൃˠݚڀ։ൃɾٕज़ࢧԉ
    w ՝֎׆ಈ
    w 1MBZ'SBNFXPSLؔ࿈ͰدߘɺొஃͳͲ
    w ͨ·ʹυϥϜΛୟ͘

    View Slide

  4. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ͸

    View Slide

  5. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ͸

    ඇػೳཁ݅(Non-functional requirement)ͱ͸ɺγεςϜઃܭ΍৘ใγε
    ςϜ։ൃ্ͷཁٻ෼ੳʹ͓͍ͯɺཁ݅ɺγεςϜཁ݅ͱ͍ͬͨػೳ໘Ҏ
    ֎ͷશൠΛࢦ͢ɻ
    ػೳཁ݅Λ࣮૷͢ΔͨΊͷઃܭ͕γεςϜઃܭͰ͋Γɺඇػೳཁ݅Λ࣮
    ૷͢ΔͨΊͷઃܭ͕γεςϜΞʔΩςΫνϟͱͳΔɻ
    ޿ٛʹ͸ɺػೳཁ݅ͱ͸γεςϜ͕ಈ࡞͢Δ಺༰ʹ͍ͭͯఆٛ͠ɺඇػ
    ೳཁ݅ͱ͸γεςϜ͕ಈ࡞͢Δํ๏Λఆٛ͢Δͱݴ͑Δɻ
    (ུ)
    ඇػೳཁ݅͸ɺγεςϜͷશମతͳಛੑͱͯ͠ɺ։ൃϓϩδΣΫτ͕੒
    ޭ͔ࣦͨ͠ഊ͔ͨ͠Ͳ͏͔ͷࢦඪͱͯ͠΋ར༻͞ΕΔɻ
    https://ja.wikipedia.org/wiki/ඇػೳཁ݅

    View Slide

  6. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ͸

    http://cloudeo.jp/word/glossary/function_nonfunction.html

    View Slide

  7. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ͸

    http://cloudeo.jp/word/glossary/function_nonfunction.html

    View Slide

  8. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ͸

    ࢲ͸ɺඇػೳͱ͍͏༻ޠ͕޷͖Ͱ͸͋Γ·ͤΜɻ
    ͜ͷ༻ޠ͕ࣔ͢Ұ෦ͷ໘͸࣮ࡍʹ͸ͱͯ΋ػೳ
    తʹࢥ͑·͢ɻ
    ಉ྅ͷҰਓSarah Taraporewalla ͸ɺ୅ΘΓʹ
    ػೳԣஅཁ݅ʢCFRɿCross-Functional
    Requirementsʣͱ͍͏༻ޠΛ࡞Γग़͠·ͨ͠ɻ
    ࢲ͸͜ͷදݱͷํ͕ͣͬͱ޷͖Ͱ͢ɻͪ͜Βͷ
    ํ͕ɺγεςϜͷৼΔ෣͍͸࣮͸ଟ͘ͷԣஅత
    ͳॲཧͷ݁Ռͱͯ͠ॳΊͯݱΕΔͱ͍͏ࣄ࣮Λ
    Α͘ද͍ͯ͠·͢ɻ
    https://www.oreilly.co.jp/books/9784873117607/

    View Slide

  9. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ͸
    w ඇػೳཁ݅ఆٛ͸Ή͔͍ͣ͠
    w ྫ
    ࣗಈंͷߪೖΛߟ͑Δ
    w ར༻࣌ؒˠ
    w ࠷ߴ଎౓ˠ
    w ৐ंఆһˠ
    w αϙʔτɾΞϑλʔέΞˠ
    w ౪೉ରࡦˠ
    w ೩අˠ
    w FUDˠ

    View Slide

  10. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ͸
    w ඇػೳཁ݅ఆٛ͸Ή͔͍ͣ͠
    w ྫ
    ࣗಈंͷߪೖΛߟ͑Δ
    w ར༻࣌ؒˠ͍ͭͰ΋޷͖ͳͱ͖ʹ৐Γ͍ͨʂ
    w ࠷ߴ଎౓ˠ
    w ৐ंఆһˠ
    w αϙʔτɾΞϑλʔέΞˠ
    w ౪೉ରࡦˠ౪·ΕΔͷ͸ઈରʹࠔΔʂ
    w ೩අˠ
    w FUDˠ

    ઈରʹৡΕͳ͍
    ͱࢥ͍ࠐΜͰ͍Δ

    ཁٻ

    View Slide

  11. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ͸
    w ඇػೳཁ݅ఆٛ͸Ή͔͍ͣ͠
    w ྫ
    ࣗಈंͷߪೖΛߟ͑Δ
    w ར༻࣌ؒˠ͍ͭͰ΋޷͖ͳͱ͖ʹ৐Γ͍ͨʂ
    w ࠷ߴ଎౓ˠLNI
    w ৐ंఆһˠਓ
    w αϙʔτɾΞϑλʔέΞˠ
    w ౪೉ରࡦˠ౪·ΕΔͷ͸ઈରʹࠔΔʂ
    w ೩අˠ
    w FUDˠ

    ۩ମతͳ Α͏ʹݟ͑Δ

    ཁٻ

    View Slide

  12. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ͸
    w ඇػೳཁ݅ఆٛ͸Ή͔͍ͣ͠
    w ྫ
    ࣗಈंͷߪೖΛߟ͑Δ
    w ར༻࣌ؒˠ͍ͭͰ΋޷͖ͳͱ͖ʹ৐Γ͍ͨʂ
    w ࠷ߴ଎౓ˠLNI
    w ৐ंఆһˠਓ
    w αϙʔτɾΞϑλʔέΞˠ΋ͪΖΜॆ࣮͍ͯ͠Δ΄͏͕
    w ౪೉ରࡦˠ౪·ΕΔͷ͸ઈରʹࠔΔʂ
    w ೩අˠͦͦ͜͜ྑ͚Ε͹
    w FUDˠ

    අ༻ରޮՌΛ۩ମతʹ
    ΠϝʔδͰ͖ͳ͍߲໨

    View Slide

  13. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ͸
    w ඇػೳཁ݅ఆٛ͸Ή͔͍ͣ͠
    w ྫ
    ࣗಈंͷߪೖΛߟ͑Δ
    w ར༻࣌ؒˠ͍ͭͰ΋޷͖ͳͱ͖ʹ৐Γ͍ͨʂ
    w ࠷ߴ଎౓ˠLNI
    w ৐ंఆһˠਓ
    w αϙʔτɾΞϑλʔέΞˠ΋ͪΖΜॆ࣮͍ͯ͠Δ΄͏͕
    w ౪೉ରࡦˠ౪·ΕΔͷ͸ઈରʹࠔΔʂ
    w ೩අˠͦͦ͜͜ྑ͚Ε͹
    w FUDˠͦͷଞʹݕ౼͢΂͖ࣄ߲͸ʁ

    ͦ΋ͦ΋ݕ౼͢΂͖
    ߲໨͕Α͘෼͔Βͳ͍

    View Slide

  14. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ

    https://www.ipa.go.jp/files/000005076.pdf

    View Slide

  15. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ

    View Slide

  16. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ

    View Slide

  17. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ

    View Slide

  18. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ

    View Slide

  19. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ

    View Slide

  20. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ

    View Slide

  21. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ
    w ϞσϧγεςϜΛબΜͰ֤߲໨ͷϨϕϧΛௐઅ͢Δ
    w ྫ
    ࣗಈंͷߪೖΛߟ͑Δ
    w ར༻࣌ؒˠ͍ͭͰ΋޷͖ͳͱ͖ʹ৐Γ͍ͨʂ
    w ࠷ߴ଎౓ˠLNI
    w ৐ंఆһˠਓ
    w αϙʔτɾΞϑλʔέΞˠ΋ͪΖΜॆ࣮͍ͯ͠Δ΄͏͕
    w ౪೉ରࡦˠ౪·ΕΔͷ͸ઈରʹࠔΔʂ
    w ೩අˠͦͦ͜͜ྑ͚Ε͹
    w FUDˠͦͷଞʹݕ౼͢΂͖ࣄ߲͸ʁ

    View Slide

  22. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ
    w ϞσϧγεςϜΛબΜͰ֤߲໨ͷϨϕϧΛௐઅ͢Δ
    w ྫ
    ࣗಈंͷߪೖΛߟ͑Δ
    w ར༻࣌ؒˠฏ೔னؒ ʙ
    ͸ར༻͠ͳ͍
    w ࠷ߴ଎౓ˠLNI
    w ৐ंఆһˠਓ
    w αϙʔτɾΞϑλʔέΞˠ΋ͪΖΜॆ࣮͍ͯ͠Δ΄͏͕
    w ౪೉ରࡦˠ԰಺றं৔ʴϋϯυϧϩοΫ
    w ೩අˠͦͦ͜͜ྑ͚Ε͹
    w FUDˠͦͷଞʹݕ౼͢΂͖ࣄ߲͸ʁ

    ݱ࣮తͳϨϕϧʹ
    ௐઅͨ͠ཁٻ

    View Slide

  23. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ
    w ϞσϧγεςϜΛબΜͰ֤߲໨ͷϨϕϧΛௐઅ͢Δ
    w ྫ
    ࣗಈंͷߪೖΛߟ͑Δ
    w ར༻࣌ؒˠฏ೔னؒ ʙ
    ͸ར༻͠ͳ͍
    w ࠷ߴ଎౓ˠLNI ۓٸ࣌ͷΈLNI

    w ৐ंఆһˠਓ
    w αϙʔτɾΞϑλʔέΞˠ΋ͪΖΜॆ࣮͍ͯ͠Δ΄͏͕
    w ౪೉ରࡦˠ԰಺றं৔ʴϋϯυϧϩοΫ
    w ೩අˠͦͦ͜͜ྑ͚Ε͹
    w FUDˠͦͷଞʹݕ౼͢΂͖ࣄ߲͸ʁ

    ݕ౼ͷ݁Ռɺௐઅͨ͠ཁٻ

    View Slide

  24. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ
    w ϞσϧγεςϜΛબΜͰ֤߲໨ͷϨϕϧΛௐઅ͢Δ
    w ྫ
    ࣗಈंͷߪೖΛߟ͑Δ
    w ར༻࣌ؒˠฏ೔னؒ ʙ
    ͸ར༻͠ͳ͍
    w ࠷ߴ଎౓ˠLNI ۓٸ࣌ͷΈLNI

    w ৐ंఆһˠਓ
    w αϙʔτɾΞϑλʔέΞˠ΋ͪΖΜॆ࣮͍ͯ͠Δ΄͏͕
    w ౪೉ରࡦˠ԰಺றं৔ʴϋϯυϧϩοΫ
    w ೩අˠͦͦ͜͜ྑ͚Ε͹
    w FUDˠͦͷଞʹݕ౼͢΂͖ࣄ߲͸ʁ

    ݕ౼ͷ݁Ռɺௐઅͷඞཁ͕
    ແ͔ͬͨཁٻ

    View Slide

  25. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ
    w ϞσϧγεςϜΛબΜͰ֤߲໨ͷϨϕϧΛௐઅ͢Δ
    w ྫ
    ࣗಈंͷߪೖΛߟ͑Δ
    w ར༻࣌ؒˠฏ೔னؒ ʙ
    ͸ར༻͠ͳ͍
    w ࠷ߴ଎౓ˠLNI ۓٸ࣌ͷΈLNI

    w ৐ंఆһˠਓ
    w αϙʔτɾΞϑλʔέΞˠֹ݄̋ઍԁͷอݥʹՃೖ
    w ౪೉ରࡦˠ԰಺றं৔ʴϋϯυϧϩοΫ
    w ೩අˠLNὙҎ্
    w FUDˠͦͷଞʹݕ౼͢΂͖ࣄ߲͸ʁ

    අ༻ରޮՌΛ۩ମతʹ
    Πϝʔδܾͯ͠ఆͨ͠ཁٻ

    View Slide

  26. ++6($$$4QSJOHDDD@H
    ඇػೳཁٻάϨʔυ
    w ϞσϧγεςϜΛબΜͰ֤߲໨ͷϨϕϧΛௐઅ͢Δ
    w ྫ
    ࣗಈंͷߪೖΛߟ͑Δ
    w ར༻࣌ؒˠฏ೔னؒ ʙ
    ͸ར༻͠ͳ͍
    w ࠷ߴ଎౓ˠLNI ۓٸ࣌ͷΈLNI

    w ৐ंఆһˠਓ
    w αϙʔτɾΞϑλʔέΞˠֹ݄̋ઍԁͷอݥʹՃೖ
    w ౪೉ରࡦˠ԰಺றं৔ʴϋϯυϧϩοΫ
    w ೩අˠLNὙҎ্
    w ೩ྉλϯΫ༰ྔˠὙҎ্
    w ഉؾྔˠ DDʙ DD

    ౰ॳ͸ݕ౼͔Β࿙Ε͍ͯͨ
    ߲໨

    View Slide

  27. ++6($$$4QSJOHDDD@H
    w ඇػೳཁ߲݅໨Λͭͷେ߲໨ɺͷத߲໨ʹ෼ྨ

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    ඇػೳཁٻάϨʔυ

    View Slide

  28. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ4QSJOH#PPU
    w ඇػೳཁ݅ͷҰ෦͸ϑϨʔϜϫʔΫ΍ϥΠϒϥϦͰରԠͰ͖Δ

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    Spring Cloud
    (ຊηογϣϯର৅֎)

    View Slide

  29. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ4QSJOH#PPU
    w ඇػೳཁ݅ͷҰ෦͸ϑϨʔϜϫʔΫ΍ϥΠϒϥϦͰରԠͰ͖Δ

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    Spring Boot
    Actuator

    View Slide

  30. ++6($$$4QSJOHDDD@H
    ඇػೳཁ݅ͱ4QSJOH#PPU
    w ඇػೳཁ݅ͷҰ෦͸ϑϨʔϜϫʔΫ΍ϥΠϒϥϦͰରԠͰ͖Δ

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    Spring Security
    & Others

    View Slide

  31. ++6($$$4QSJOHDDD@H
    Spring Boot Actuator

    (͜͜·Ͱ10෼ͳΒΑ͍ϖʔε)

    View Slide

  32. ++6($$$4QSJOHDDD@H
    4QSJOH#PPU"DUVBUPS
    w ӡ༻ɾอकੑʹؔ͢Δཁ݅ͱ4QSJOH#PPU"DUVBUPS

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    w ӡ༻࣌ؒ
    w όοΫΞοϓ
    w ӡ༻؂ࢹ
    w ࣌ࠁಉظ
    Spring Boot
    Actuator
    w ܭըఀࢭ
    w ӡ༻ෛՙܰݮ
    w ύονద༻ϙϦγʔ
    w ׆ੑอक
    w ఆظอकස౓
    w ༧๷อकϨϕϧ

    View Slide

  33. ++6($$$4QSJOHDDD@H
    4QSJOH#PPU"DUVBUPS
    w ӡ༻ɾอकੑʹؔ͢Δཁ݅ͱ4QSJOH#PPU"DUVBUPS

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    w ӡ༻࣌ؒ
    w όοΫΞοϓ
    w ӡ༻؂ࢹ
    w ࣌ࠁಉظ
    w ܭըఀࢭ
    w ӡ༻ෛՙܰݮ
    w ύονద༻ϙϦγʔ
    w ׆ੑอक
    w ఆظอकස౓
    w ༧๷อकϨϕϧ
    Spring Boot
    Actuator

    View Slide

  34. ++6($$$4QSJOHDDD@H
    4QSJOH#PPU"DUVBUPSͱ͸
    w l1SPEVDUJPOSFBEZGFBUVSFTz
    w )551·ͨ͸+.9ͰΞϓϦέʔγϣϯΛϞχλϦϯάɺ؅ཧ
    w 4QSJOH#PPU͔Β44)͸ඇਪ঑
    w 4QSJOH.7$্Ͱಈ࡞
    w ؆୯Πϯετʔϧ
    w ߴ͍ΧελϚΠζੑͱ֦ுੑ

    View Slide

  35. ++6($$$4QSJOHDDD@H
    4QSJOH#PPU"DUVBUPSͱ͸
    w Πϯετʔϧ͸ґଘੑΛ௥Ճ͢Δ͚ͩ


    org.springframework.boot
    spring-boot-starter-actuator

    EndpointHandlerMapping : Mapped "{[/beans || /beans.json],methods=[GET],produces=[a
    EndpointHandlerMapping : Mapped "{[/loggers/{name:.*}],methods=[GET],produces=[appl
    EndpointHandlerMapping : Mapped "{[/loggers/{name:.*}],methods=[POST],consumes=[app
    EndpointHandlerMapping : Mapped "{[/loggers || /loggers.json],methods=[GET],produce
    EndpointHandlerMapping : Mapped "{[/metrics/{name:.*}],methods=[GET],produces=[appl
    EndpointHandlerMapping : Mapped "{[/metrics || /metrics.json],methods=[GET],produce
    EndpointHandlerMapping : Mapped "{[/dump || /dump.json],methods=[GET],produces=[app
    EndpointHandlerMapping : Mapped "{[/auditevents || /auditevents.json],methods=[GET]
    EndpointHandlerMapping : Mapped "{[/health || /health.json],methods=[GET],produces=
    EndpointHandlerMapping : Mapped "{[/info || /info.json],methods=[GET],produces=[app
    EndpointHandlerMapping : Mapped "{[/env/{name:.*}],methods=[GET],produces=[applicat
    EndpointHandlerMapping : Mapped "{[/env || /env.json],methods=[GET],produces=[appli
    EndpointHandlerMapping : Mapped "{[/mappings || /mappings.json],methods=[GET],produ
    EndpointHandlerMapping : Mapped "{[/heapdump || /heapdump.json],methods=[GET],produ
    EndpointHandlerMapping : Mapped "{[/configprops || /configprops.json],methods=[GET]
    EndpointHandlerMapping : Mapped "{[/trace || /trace.json],methods=[GET],produces=[a
    EndpointHandlerMapping : Mapped "{[/autoconfig || /autoconfig.json],methods=[GET],p
    ΤϯυϙΠϯτ͕
    ଟ਺௥Ճ͞ΕΔ

    View Slide

  36. ++6($$$4QSJOHDDD@H
    4QSJOH#PPU"DUVBUPSͱ͸

    ௥Ճ͞ΕͨΤϯυϙΠϯτʹ
    )551ͰΞΫηε͢Δͱ
    ֤छ৘ใΛ+40/ͰऔಘͰ͖Δ

    View Slide

  37. ++6($$$4QSJOHDDD@H
    4QSJOH#PPU"DUVBUPSͱ͸

    +40/7JFXϓϥάΠϯͳͲͰ
    ੔ܗͯ͠ݕࡧ͢Δͱݟқ͍

    View Slide

  38. ++6($$$4QSJOHDDD@H
    4QSJOH#PPU"DUVBUPSͱ͸

    $ curl localhost:8080/configprops \
    > | jq .dataSource.properties.poolProperties
    {
    "dbProperties": {
    "user": "sa",
    "password": "******"
    },
    "url": “jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON...
    "driverClassName": "org.h2.Driver",
    "defaultAutoCommit": null,
    "defaultReadOnly": null,
    "defaultTransactionIsolation": -1,
    "defaultCatalog": null,
    "connectionProperties": null,
    "initialSize": 10,
    "maxActive": 100,
    "maxIdle": 100,
    "maxWait": 3000,
    ...
    DVSMͰΞΫηεͯ͠KRͰ੔ܗɺ
    ϑΟϧλͯ͠΋ྑ͍

    View Slide

  39. ++6($$$4QSJOHDDD@H
    ઃఆ
    w "DUVBUPSશମͷઃఆ
    w BQQMJDBUJPOQSPQFSUJFTʹlNBOBHFNFOUzͰઃఆ

    # ઀ଓΛड͚෇͚ΔΞυϨεͱϙʔτ൪߸
    management.address=127.0.0.1
    management.port=9999
    # Actuatorͷϧʔτύε
    management.context-path=/ops
    # ActuatorͷηΩϡϦςΟઃఆΛແޮʹ͢Δ
    # ΞυϨε΍ϙʔτ൪߸ͰηΩϡϦςΟ͕֬อͰ͖͍ͯΔ৔߹ͷΈઃఆ͢Δ͜ͱ
    management.security.enabled=false
    # ActuatorʹΞΫηεͰ͖Δϩʔϧ
    # Spring Boot 1.5͔ΒσϑΥϧτ͸'ACTUATOR'ʹมߋ
    #management.security.roles=ADMIN

    View Slide

  40. ++6($$$4QSJOHDDD@H
    ઃఆ
    w ΤϯυϙΠϯτ͝ͱͷઃఆ
    w BQQMJDBUJPOQSPQFSUJFTʹlFOEQPJOUT\JE^zͰઃఆ

    # ࢦఆͨ͠ΤϯυϙΠϯτΛ༗ޮ/ແޮʹ͢Δ
    endpoints.shutdown.enabled=true
    # ࢦఆͨ͠ΤϯυϙΠϯτΛೝূཁ/ෆཁʹ͢Δ
    endpoints.health.sensitive=false
    # ࢦఆͨ͠ΤϯυϙΠϯτͷIDΛมߋ͢Δ
    endpoints.dump.id=threaddump
    # idΛলུͯ͢͠΂ͯͷΤϯυϙΠϯτΛҰׅઃఆ͢Δ͜ͱ΋Ͱ͖Δ
    #endpoints.enabled=false

    View Slide

  41. ++6($$$4QSJOHDDD@H
    &OEQPJOUT

    View Slide

  42. ++6($$$4QSJOHDDD@H
    &OEQPJOUT

    ຊηογϣϯͷઆ໌ର৅

    View Slide

  43. ++6($$$4QSJOHDDD@H
    BVEJUFWFOUT
    w 4QSJOH4FDVSJUZ͕ൃߦͨ͠ೝূɾೝՄΠϕϯτ
    w ϝϞϦʹ஝ੵ͞ΕͨΠϕϯτΛશ݅දࣔ

    $ curl localhost:9999/ops/auditevents | jq '.events[0]'
    {
    "timestamp": "2017-05-07T14:24:01+0000",
    "principal": "anonymousUser",
    "type": "AUTHORIZATION_FAILURE",
    "data": {
    "details": {
    "remoteAddress": "0:0:0:0:0:0:0:1",
    "sessionId": null
    },
    "type":
    “org.springframework.security.access.AccessDeniedException",
    "message": "Access is denied"
    }
    }

    View Slide

  44. ++6($$$4QSJOHDDD@H
    BVEJUFWFOUT
    w ϦΫΤετύϥϝʔλͰϑΟϧλϦϯά
    w QSJODJQBM ೝূϢʔβ

    w BGUFS Πϕϯτൃੜ೔࣌

    w UZQF Πϕϯτछผ


    $ curl http://localhost:9999/ops/auditevents\
    > \?principal=admin\
    > \&after=2017-05-07T12%3A00%3A00%2B0000\
    > \&type=AUTHENTICATION_FAILURE | jq '.events[0]'
    {
    "timestamp": "2017-05-07T14:24:13+0000",
    "principal": "admin",
    "type": "AUTHENTICATION_FAILURE",
    ...
    }
    bBENJO`Ϣʔβ͕
    Ҏ߱ʹ
    ೝূࣦഊͨ͠ΠϕϯτΛநग़

    View Slide

  45. ++6($$$4QSJOHDDD@H
    IFBMUI
    w ΞϓϦέʔγϣϯ΍ϛυϧ΢ΣΞͷࢮ׆؂ࢹ
    w σϑΥϧτͰ֤छ3%#.4 3BCCJU.2 3FEJTͳͲʹରԠ
    w ಠࣗʹ؂ࢹ߲໨Λ௥Ճ͢Δ͜ͱ΋Ͱ͖Δ

    $ curl localhost:9999/ops/health | jq .
    {
    "status": "UP",
    "diskSpace": {
    "status": "UP",
    "total": 250140434432,
    "free": 26348904448,
    "threshold": 10485760
    },
    "db": {
    "status": "UP",
    "database": "H2",
    "hello": 1
    }
    }
    ࢮ׆؂ࢹํ๏͸੡඼ґଘͰɺ
    )ͷ৔߹͸l4&-&$5zΛ
    ౤͛Δ
    σϑΥϧτ͸TFOTJUJWFUSVFͳͷͰ
    ະೝূঢ়ଶͰ͸ΞϓϦέʔγϣϯ
    TUBUVTͷΈදࣔ͞ΕΔ

    View Slide

  46. ++6($$$4QSJOHDDD@H
    JOGP
    w σϑΥϧτ͸Կ΋දࣔ͞Εͳ͍
    w BQQMJDBUJPOQSPQFSUJFTʹlJOGPz͕͋Ε͹දࣔ
    w l!!ͰQPNYNMͷ಺༰ΛࢦఆͰ͖Δ
    w l\^ͰγεςϜϓϩύςΟͷ಺༰ΛࢦఆͰ͖Δ

    [email protected]@
    [email protected]@
    info.app.os_name=${os.name}
    info.app.misc=xxx
    $ curl localhost:9999/ops/info | jq '.app'
    {
    "version": "0.0.1-SNAPSHOT",
    "name": "ccc-g1",
    “os_name”: "Mac OS X",
    "misc": "xxx"
    }

    View Slide

  47. ++6($$$4QSJOHDDD@H
    JOGP
    w HJUQSPQFSUJFT͕͋Ε͹දࣔ
    w HJUDPNNJUJEQMVHJOΛQPNYNMʹ௥Ճ͢Δ



    pl.project13.maven
    git-commit-id-plugin


    $ curl localhost:9999/ops/info | jq '.git'
    {
    "commit": {
    "time": 1493972299000,
    "id": "b2c28ef"
    },
    "branch": "master"
    }
    ΞϓϦέʔγϣϯͷϒϥϯν΍
    ίϛοτ*%͕දࣔ͞ΕΔ

    View Slide

  48. ++6($$$4QSJOHDDD@H
    JOGP
    w .&5"*/'CVJMEJOGPQSPQFSUJFT͕͋Ε͹දࣔ
    w TQSJOHCPPUCVJMEJOGPΰʔϧΛ࣮ߦ͢Δ

    $ curl localhost:9999/ops/info | jq '.build'
    {
    "version": "0.0.1-SNAPSHOT",
    "artifact": "ccc-g1",
    "name": "ccc-g1",
    "group": "com.example",
    "time": 1494213456000
    }
    $ mvn spring-boot:build-info
    (snip)
    $ ls target/classes/META-INF
    build-info.properties
    ΞϓϦέʔγϣϯͷόʔδϣϯ΍
    Ϗϧυ͕ͨ࣌ؒ͠දࣔ͞ΕΔ

    View Slide

  49. ++6($$$4QSJOHDDD@H
    MPHHFST
    w ϩάϨϕϧΛ֬ೝͰ͖Δ
    w l\OBNF^zͰ໊લΛࢦఆͯ֬͠ೝ͢Δ͜ͱ΋Ͱ͖Δ

    $ curl localhost:9999/ops/loggers/\
    > org.springframework.security | jq .
    {
    "configuredLevel": null,
    "effectiveLevel": "INFO"
    }
    $ curl localhost:9999/ops/loggers | jq '.loggers'
    {
    "ROOT": {
    "configuredLevel": "INFO",
    "effectiveLevel": "INFO"
    },
    ...
    } 4QSJOH4FDVSJUZͷ
    ϩάϨϕϧ͸*/'0

    View Slide

  50. ++6($$$4QSJOHDDD@H
    MPHHFST
    w 4QSJOH#PPU͔Βӡ༻தʹϩάϨϕϧͷมߋ͕Մೳʹʂ

    $ curl -X POST \
    > -H 'Content-Type: application/json' \
    > -d '{"configuredLevel":"DEBUG"}' \
    > localhost:9999/ops/loggers/\
    > org.springframework.security
    ...
    o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHo
    o.s.security.web.FilterChainProxy : / at position 10 of 13 in a
    o.s.security.web.FilterChainProxy : / at position 11 of 13 in a
    o.s.security.web.FilterChainProxy : / at position 12 of 13 in a
    o.s.security.web.FilterChainProxy : / at position 13 of 13 in a
    o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /' doesn't mat
    o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request :
    o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request :
    o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvoca
    o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: o
    o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.
    o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is a
    ...
    4QSJOH4FDVSJUZͷϩάϨϕϧΛ
    %(ʹมߋ͢Δͱେྔʹϩά͕
    ग़ྗ͞Εͯศར

    MPHHFS໊Λࢦఆͯ͠
    ϩάϨϕϧΛ+40/Ͱ
    1045͢Δ

    View Slide

  51. ++6($$$4QSJOHDDD@H
    NFUSJDT
    w $16ɺϝϞϦɺεϨουͳͲͷϝτϦΫε৘ใ

    $ curl localhost:9999/ops/metrics | jq .
    {
    "mem": 463639,
    "mem.free": 283297,
    "processors": 2,
    "instance.uptime": 1234698,
    "uptime": 1252089,
    "systemload.average": 5.4296875,
    "heap.committed": 385024,
    "heap.init": 65536,
    "heap.used": 101726,
    "heap": 932352,
    "nonheap.committed": 87360,
    "nonheap.init": 2496,
    "nonheap.used": 84960,
    ...
    }

    View Slide

  52. ++6($$$4QSJOHDDD@H
    NFUSJDT
    w &YQPSUFSΛ࣮૷ͯ͠3FEJT΍4UBUT%ʹΤΫεϙʔτͰ͖Δ
    w σϑΥϧτͰ.#FBO&YQPSUFS͕༗ޮ

    View Slide

  53. ++6($$$4QSJOHDDD@H
    USBDF
    w ௚ۙ݅ͷΞΫηεϩά

    $ curl localhost:9999/ops/trace | jq '.[0]'
    {
    "timestamp": 1494175457526,
    "info": {
    "method": "GET",
    "path": "/",
    "headers": {
    "request": {
    "host": “localhost:8080",
    ...
    },
    "response": {
    ...
    "status": "200"
    }
    }
    }
    }

    View Slide

  54. ++6($$$4QSJOHDDD@H
    ͦͷଞ
    w ։ൃ޻ఔ
    w BVUPDPOpHˠ4QSJOH#PPU͕ࣗಈతʹߦͬͨઃఆ৘ใ
    w CFBOTˠ%*ίϯςφʹొ࿥͞Εͨ#FBOͷҰཡ
    w QSPQDPOpHTˠΞϓϦέʔγϣϯͷઃఆ৘ใ
    w ӡ༻ɾอक޻ఔ
    w EVNQˠεϨουμϯϓ
    w IFBQEVNQˠώʔϓμϯϓΛμ΢ϯϩʔυͰ͖Δ
    w MPHpMFˠϩάϑΝΠϧΛμ΢ϯϩʔυͰ͖Δ
    w NBQQJOHTˠϦΫΤετϚοϐϯάҰཡ

    (͜͜·Ͱ20෼ͳΒΑ͍ϖʔε)

    View Slide

  55. ++6($$$4QSJOHDDD@H
    &OEQPJOUΛ௥Ճ͢Δ
    w ಠࣗͷΤϯυϙΠϯτΛ௥Ճ͢Δ

    // package and imports...
    @Component
    public class CustomEndpoint
    implements Endpoint> {
    @Override
    public String getId() { return "custom"; }
    @Override
    public boolean isEnabled() { return true; }
    @Override
    public boolean isSensitive() { return true; }
    @Override
    public List invoke() {
    return Arrays.asList("one", "two", "three");
    }
    }
    &OEQPJOU5Λ࣮૷͢Δ
    μϛʔͷ࣮૷ྫɻ
    ࣮ࡍ͸%*ίϯςφ΍σʔλϕʔε
    ͔Β஋Λऔಘͯ͠ฦ͢

    View Slide

  56. ++6($$$4QSJOHDDD@H
    &OEQPJOUΛ௥Ճ͢Δ
    w ࣗಈతʹݕग़͞ΕͯΤϯυϙΠϯτʹ௥Ճ͞ΕΔ

    $ curl localhost:9999/ops/custom | jq .
    [
    "one",
    "two",
    "three"
    ]
    ...
    EndpointHandlerMapping : Mapped “{[/ops/loggers/{name:.*}],methods
    EndpointHandlerMapping : Mapped “{[/ops/loggers/{name:.*}],methods
    EndpointHandlerMapping : Mapped “{[/ops/loggers || /loggers.json],
    EndpointHandlerMapping : Mapped “{[/ops/custom || /custom.json],me
    EndpointHandlerMapping : Mapped “{[/ops/trace || /trace.json],meth
    EndpointHandlerMapping : Mapped “{[/ops/actuator || /actuator.json
    EndpointHandlerMapping : Mapped “{[/ops/heapdump || /heapdump.json
    ...

    View Slide

  57. ++6($$$4QSJOHDDD@H
    &OEQPJOUΛ֦ு͢Δ
    w طଘͷΤϯυϙΠϯτΛ֦ு͢Δ

    // package and imports...
    @Component
    public class MappingsMvcEndpoint extends EndpointMvcAdapter {
    private final RequestMappingEndpoint delegate;
    public MappingsMvcEndpoint(
    RequestMappingEndpoint delegate) {
    super(delegate);
    this.delegate = delegate;
    }
    @GetMapping("html")
    public ModelAndView html() {
    Map result = delegate.invoke();
    return new ModelAndView("mappings", "result", result);
    }
    }
    طଘͷΤϯυϙΠϯτʹॲཧΛ
    ҕৡ͠ɺ݁ՌΛՃ޻ɾදࣔ͢Δ
    &OEQPJOU.WD"EBQUFSΛ
    ܧঝ͢Δ

    View Slide

  58. ++6($$$4QSJOHDDD@H
    &OEQPJOUΛ֦ு͢Δ

    View Slide

  59. ++6($$$4QSJOHDDD@H
    &OEQPJOUΛ֦ு͢Δ
    w ΤΫηϧΤϯυϙΠϯτ


    org.apache.poi
    poi-ooxml
    3.16

    @GetMapping("xlsx")
    public ModelAndView xlsx() {
    return new ModelAndView(new AbstractXlsxView() {
    @Override
    protected void buildExcelDocument(
    Map model, Workbook workbook,
    HttpServletRequest request,
    HttpServletResponse response) throws Exception {
    // (snip)
    }
    });
    }
    PSHTQSJOHGSBNFXPSLXFCTFSWMFU
    WJFXEPDVNFOU"CTUSBDU9MTY7JFX
    Λ࡞ͬͯฦ͢

    View Slide

  60. ++6($$$4QSJOHDDD@H
    &OEQPJOUΛ֦ு͢Δ

    View Slide

  61. ++6($$$4QSJOHDDD@H
    4QSJOH#PPU"DUVBUPS·ͱΊ
    w l1SPEVDUJPOSFBEZGFBUVSFTz
    w )551·ͨ͸+.9ͰΞϓϦέʔγϣϯΛϞχλϦϯάɺ؅ཧ
    w ؆қͳӡ༻ɾอकʹ࠷ద
    w ։ൃʹ΋༗༻
    w ؆୯Πϯετʔϧ
    w ґଘੑΛ௥Ճ͢Δ͚ͩ
    w ߴ͍ΧελϚΠζੑͱ֦ுੑ
    w BQQMJDBUJPOQSPQFSUJFTͰॊೈʹઃఆ
    w ΤϯυϙΠϯτͷ௥Ճɺ֦ு΋Մೳ

    View Slide

  62. ++6($$$4QSJOHDDD@H
    4QSJOH4FDVSJUZ
    0UIFST

    (͜͜·Ͱ25෼ͳΒΑ͍ϖʔε)
    (ਫΛҿΉ)

    View Slide

  63. ++6($$$4QSJOHDDD@H
    4QSJOH4FDVSJUZ0UIFST
    w ηΩϡϦςΟʹؔ͢Δཁ݅ͱ4QSJOH4FDVSJUZͦͷଞ

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    Spring Security
    & Others

    View Slide

  64. ++6($$$4QSJOHDDD@H
    4QSJOH4FDVSJUZ0UIFST
    w ΞΫηεɾར༻੍ݶ

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    Spring Security
    & Others
    w ೝূػೳ
    w ར༻੍ݶ
    w ؅ཧํ๏

    View Slide

  65. ++6($$$4QSJOHDDD@H
    4QSJOH4FDVSJUZ0UIFST
    w ΞΫηεɾར༻੍ݶ

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    Spring Security
    & Others
    w ೝূػೳ
    w ύεϫʔυॳظԽ
    w ύεϫʔυϙϦγʔ
    w ύεϫʔυޡೖྗ๷ࢭ
    w ύεϫʔυ༗ޮظݶ
    w ύεϫʔυੈ୅؅ཧ
    w ΞΧ΢ϯτϩοΫ
    w ΞΧ΢ϯτແޮԽ
    w FUD
    w ར༻੍ݶ
    w ؅ཧํ๏
    ຊηογϣϯͷઆ໌ൣғ

    View Slide

  66. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ύεϫʔυϙϦγʔ

    w lจࣈҎ্ɺେখ਺ࣈΛͦΕͧΕจࣈҎ্zΈ͍ͨͳΞϨ

    http://www.passay.org/

    View Slide

  67. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ύεϫʔυϙϦγʔ

    w ґଘੑΛ௥Ճͯ͠ΞϊςʔγϣϯΛ࡞Δ


    org.passay
    passay
    1.2.0

    // package and imports...
    @Documented
    @Retention(RUNTIME)
    @Target(FIELD)
    @Constraint(validatedBy = PasswordConstraintValidator.class)
    public @interface ValidPassword {
    String message() default "Invalid Password";
    Class>[] groups() default {};
    Class extends Payload>[] payload() default {};
    }
    ۩ମతͳݕূॲཧ͸1BTTBZͰ
    ࣮૷͢Δ

    View Slide

  68. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ύεϫʔυϙϦγʔ

    w ۩ମతͳݕূॲཧ͸ϧʔϧΛ૊Έ߹Θͤͯ࡞Δ

    // package and imports...
    import static org.passay.EnglishCharacterData.*;
    public class PasswordConstraintValidator implements
    ConstraintValidator {
    // (snip)
    @Override
    public boolean isValid(String password,
    ConstraintValidatorContext context) {
    PasswordValidator validator =
    new PasswordValidator(Arrays.asList(
    new LengthRule(8),
    new CharacterRule(UpperCase, 1),
    new CharacterRule(LowerCase, 1),
    new CharacterRule(Digit, 1)));
    RuleResult result =
    validator.validate(new PasswordData(password));
    // (snip)
    }
    จࣈҎ্ɺ
    େจࣈɺখจࣈɺ਺ࣈ
    ͦΕͧΕจࣈҎ্

    View Slide

  69. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ύεϫʔυϙϦγʔ

    w ϑΥʔϜʹద༻ͯ͠ίϯτϩʔϥͰར༻͢Δ

    // package and imports...
    public class PasswordForm {
    @ValidPassword
    private String password;
    // getters/setters...
    }
    ϙϦγʔΛద༻͍ͨ͠ϑΟʔϧυΛ
    ࡞੒ͨ͠ΞϊςʔγϣϯͰ஫ऍ͢Δ
    // package and imports...
    @Controller
    public class PasswordController {
    // (snip)
    @PostMapping("update")
    String update(@Validated PasswordForm form,
    BindingResult result) {
    if (result.hasErrors()) { ... }
    // (snip)
    }
    }
    l!7BMJEBUFEzͰೖྗ஋ͷଥ౰ੑΛ
    ݕূ͢Δ

    View Slide

  70. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ύεϫʔυϙϦγʔ

    w εΫϦʔϯγϣοτషΔ

    View Slide

  71. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ύεϫʔυޡೖྗ๷ࢭ

    w l֬ೝ༻ύεϫʔυ͕Ұக͠·ͤΜz͍ͬͯ͏ΞϨ
    w ૬ؔνΣοΫ༻ΞϊςʔγϣϯΛ5&3"40-6/" ˞
    ͕ఏڙ
    w ͔Β.BWFO$FOUSBMʹΞοϓϩʔυ͞Ε͍ͯΔͷͰɹ
    ґଘੑΛ௥Ճ͢Δ͚ͩͰར༻Ͱ͖Δ


    org.terasoluna.gfw
    terasoluna-gfw-validator
    5.3.0.RELEASE

    ※ TERASOLUNAʢςϥιϧφʣ͸ɺNTTσʔλ͕ఏڙ͢ΔʮϑϨʔϜϫʔΫʯɺʮ։ൃϓϩηεʯɺʮϓϩ
    δΣΫτ؅ཧʯͳͲͷٕज़΍ϊ΢ϋ΢Λ૊߹ͤɺ γεςϜ։ൃΛแׅతʹαϙʔτ͢ΔιϦϡʔγϣϯ
    http://terasolunaorg.github.io

    View Slide

  72. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ύεϫʔυޡೖྗ๷ࢭ

    w ΫϥεΛl!$PNQBSFzͰ஫ऍ͢Δ
    w lMFGUz lSJHIUzʹ૬ؔνΣοΫ͢Δ߲໨໊Λࢦఆ͢Δ
    w lPQFSBUPSzʹνΣοΫ಺༰Λࢦఆ͢Δ
    w lNFTTBHFzʹΤϥʔϝοηʔδΛࢦఆ͢Δ

    // package and imports...
    import
    org.terasoluna.gfw.common.validator.constraints.Compare;
    @Compare(left = "password", right = “password2",
    operator = Compare.Operator.EQUAL,
    message = "passwords do not match!”)
    public class PasswordForm {
    @ValidPassword
    private String password;
    private String password2;
    // getters/setters...
    }

    View Slide

  73. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ύεϫʔυޡೖྗ๷ࢭ


    View Slide

  74. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ΞΧ΢ϯτϩοΫ

    w lೝূࣦഊ࿈ଓճͰΞΧ΢ϯτϩοΫzΈ͍ͨͳΞϨ
    w 4QSJOH'SBNFXPSL͸l!&WFOU-JTUFOFSzͰ༷ʑͳΠϕϯτΛ
    ϋϯυϦϯάͰ͖Δ
    w 4QSJOH4FDVSJUZͷΞΧ΢ϯτʹ͸ҎԼͷঢ়ଶΛઃఆͰ͖Δɻ
    GBMTFͷ৔߹͸ೝূʹࣦഊ͢Δ
    w ΞΧ΢ϯτ͸༗ޮظݶ͕੾Ε͍ͯͳ͍͔
    w ΞΧ΢ϯτ͸ϩοΫ͞Ε͍ͯͳ͍͔
    w ύεϫʔυ͸༗ޮظݶ͕੾Ε͍ͯͳ͍͔
    w ΞΧ΢ϯτ͸༗ޮ͔

    View Slide

  75. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ΞΧ΢ϯτϩοΫ

    w ೝূࣦഊճ਺Λ࣋ͭΞΧ΢ϯτͱ໊લͰݕࡧͰ͖ΔϦϙδτϦ

    // package and imports...
    @Entity
    public class Account {
    @Id @GeneratedValue(strategy = AUTO)
    private Integer id;
    private String username;
    private String password;
    private int loginFailureTimes;
    private String authorities;
    // other fields, getters/setters...
    }
    // package and imports...
    public interface AccountRepository extends
    JpaRepository {
    Account findByUsername(String username);
    }

    View Slide

  76. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ΞΧ΢ϯτϩοΫ

    w ೝূΠϕϯτΛϋϯυϦϯά͢Δ

    // package and imports...
    @Component
    public class AuthenticationEventListeners {
    // fields and constructor...
    @EventListener
    public void handle(
    AuthenticationFailureBadCredentialsEvent e) {
    Account account =
    accountRepository.findByUsername(
    (String) e.getAuthentication().getPrincipal());
    if (account == null) { return; }
    account.setLoginFailureTimes(
    account.getLoginFailureTimes() + 1);
    accountRepository.save(account);
    }
    }
    l!&WFOU-JTUFOFSzͰ஫ऍͯ͠
    Ҿ਺ʹࢦఆͨ͠ܕͷΠϕϯτΛ
    ϋϯυϦϯά͢Δ
    ೝূࣦഊճ਺Λ
    ΠϯΫϦϝϯτͯ͠
    อଘ͢Δ

    View Slide

  77. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ΞΧ΢ϯτϩοΫ

    w 6TFS%FUBJMTΛ࣮૷͢Δ

    // package and imports...
    public class MyUserDetails extends User {
    private final Account account;
    public MyUserDetails(Account account,
    boolean accountNonLocked) {
    super(account.getUsername(),
    account.getPassword(),
    true, // enabled
    true, // accountNonExpired
    true, // credentialsNonExpired
    accountNonLocked,
    AuthorityUtils.
    commaSeparatedStringToAuthorityList(
    account.getAuthorities()));
    this.account = account;
    }
    }
    PSHTQSJOHGSBNFXPSL
    TFDVSJUZDPSFVTFSEFUBJMT
    6TFSΛܧঝ͢Δͱศར
    ਌ΫϥεͷίϯετϥΫλʹ
    ΞΧ΢ϯτঢ়ଶΛઃఆ͢Δɻ
    ͜͜Ͱ͸ΞΧ΢ϯτϩοΫɹ
    Ҏ֎͸શͯUSVF ༗ޮ
    ʹઃఆ
    ίϯετϥΫλͰ"DDPVOU
    ͱΞΧ΢ϯτϩοΫঢ়ଶΛ
    ड͚Δ

    View Slide

  78. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ΞΧ΢ϯτϩοΫ

    w 6TFS%FUBJMT4FSWJDFΛ࣮૷͢Δ
    w %*ίϯςφʹొ࿥͢Ε͹4QSJOH4FDVSJUZʹࣗಈద༻͞ΕΔ

    // package and imports...
    @Service
    public class MyUserDetailsService implements
    UserDetailsService {
    // fields and constructor...
    @Override
    public UserDetails loadUserByUsername(String username)
    throws UsernameNotFoundException {
    Account account =
    accountRepository.findByUsername(username);
    // error handling...
    boolean accountNonLocked =
    account.getLoginFailureTimes() < 3;
    return new MyUserDetails(account, accountNonLocked);
    }
    }
    ೝূࣦഊճ਺্͕ݶΛ௒͍͑ͯΔ͔
    ൑ఆͯ͠ίϯετϥΫλʹ౉͢

    View Slide

  79. ++6($$$4QSJOHDDD@H
    ΞΫηεɾར༻੍ݶ ΞΧ΢ϯτϩοΫ


    ΞΧ΢ϯτϩοΫঢ়ଶͷ৔߹͸
    ύεϫʔυ͕ਖ਼ͯ͘͠΋ೝূʹ
    ࣦഊ͢Δ

    ύεϫʔυ࿈ଓࣦഊճ਺্ݶʹ
    ຬͨͳ͍৔߹

    View Slide

  80. ++6($$$4QSJOHDDD@H
    4QSJOH4FDVSJUZ0UIFST
    w σʔλͷൿಗ

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    Spring Security
    & Others
    w σʔλ҉߸Խ
    w ύεϫʔυͷϋογϡԽ
    w ػີ৘ใͷ҉߸Խ
    (͜͜·Ͱ30෼ͳΒΑ͍ϖʔε)

    View Slide

  81. ++6($$$4QSJOHDDD@H
    w 4)"Ͱͳ͘#DSZQU·ͨ͸4DSZQUΛ࢖͏΂͖
    w ฏจ͸࿦֎ɺ.%ɺ4)"͸ίϦδϣϯ͕ݟ͔͍ͭͬͯΔ
    w ͦͷଞͷ4)"΋ڧ౓ΑΓ଎౓༏ઌ

    https://rietta.com/blog/2016/02/05/bcrypt-not-sha-for-passwords/
    σʔλͷൿಗ ύεϫʔυͷϋογϡԽ

    View Slide

  82. ++6($$$4QSJOHDDD@H
    σʔλͷൿಗ ύεϫʔυͷϋογϡԽ

    w 4QSJOH4FDVSJUZ͕#DSZQU 4DSZQU࣮૷Λఏڙ
    w 1BTTXPSE&ODPEFSͷ࣮૷Λ%*ίϯςφʹొ࿥͢Ε͹
    4QSJOH4FDVSJUZʹࣗಈద༻͞ΕΔ

    // package and imports...
    @Configuration
    public class SecurityConfig extends
    WebSecurityConfigurerAdapter {
    @Bean
    PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
    }
    // other configurations...
    }

    View Slide

  83. ++6($$$4QSJOHDDD@H
    σʔλͷൿಗ ύεϫʔυͷϋογϡԽ

    w ೚ҙͷαʔϏεʹΠϯδΣΫγϣϯͯ͠࢖͏

    // package and imports...
    @Service
    public class AccountService {
    private final PasswordEncoder encoder;
    public AccountService(PasswordEncoder encoder) {
    this.encoder = encoder;
    }
    public boolean updatePassword(String username,
    String rawPassword) {
    String oldPassword = // get oldPassword from database...
    if (encoder.matches(rawPassword, oldPassword) {...}
    String encoded = encoder.encode(password);
    return repository.updatePassword(username, encoded);
    }
    }
    ฏจύεϫʔυͱͷಥ߹΍ϋογϡԽ

    View Slide

  84. ++6($$$4QSJOHDDD@H
    σʔλͷൿಗ ػີ৘ใͷ҉߸Խ

    w ֤छ઀ଓ৘ใͳͲΛ ϋογϡԽͰ͸ͳ͘
    ҉߸Խ͢Δ

    http://www.jasypt.org/

    View Slide

  85. ++6($$$4QSJOHDDD@H
    σʔλͷൿಗ ػີ৘ใͷ҉߸Խ

    w KBTZQUTQSJOHCPPUTUBSUFS͕ఏڙ͞Ε͍ͯΔ

    https://github.com/ulisesbocchio/jasypt-spring-boot

    View Slide

  86. ++6($$$4QSJOHDDD@H
    σʔλͷൿಗ ػີ৘ใͷ҉߸Խ

    w ґଘੑΛ௥Ճͯ͠҉߸Λ࡞Δ


    com.github.ulisesbocchio
    jasypt-spring-boot-starter
    1.12

    $ java -cp \
    > ~/.m2/repository/org/jasypt/jasypt/1.9.2/jasypt-1.9.2.jar \
    > org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI \
    > input=sa \
    > password=secretkey \
    > algorithm=PBEWithMD5AndDES
    ...
    ----OUTPUT----------------------
    0L8y9EPEsdYc76viCxUAsQ== ಘΒΕͨ҉߸
    )ͷ઀ଓϢʔβ໊Λ҉߸Խ͢Δྫɻ
    ҉߸Խ͢Δ஋ɺ伴ɺΞϧΰϦζϜΛ
    ࢦఆͯ͠҉߸ԽॲཧΛ࣮ߦ

    View Slide

  87. ++6($$$4QSJOHDDD@H
    σʔλͷൿಗ ػີ৘ใͷ҉߸Խ

    w BQQMJDBUJPOQSPQFSUJFTʹ҉߸ͱݤΛઃఆ͢Δ

    # DATASOURCE
    spring.datasource.username=ENC(0L8y9EPEsdYc76viCxUAsQ==)
    # JASYPT
    #jasypt.encryptor.password=secretkey
    jasypt.encryptor.password=${JASYPT_ENCRYPTOR_PASSWORD}
    $ export JASYPT_ENCRYPTOR_PASSWORD=secretkey
    l&/$
    zͰғΜͰෳ߹ର৅Ͱ
    ͋Δ͜ͱΛࣔ͢
    伴Λ௚઀ઃఆ͢ΔͱηΩϡϦςΟڧ౓తʹ
    ͋·Γҙຯ͕ͳ͍
    ؀ڥม਺ͳͲ͔ΒಡΈࠐΜͰࢦఆ͢Δ

    View Slide

  88. ++6($$$4QSJOHDDD@H
    4QSJOH4FDVSJUZ0UIFST
    w ෆਖ਼௥੻ɾ؂ࢹ

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    Spring Security
    & Others
    w ෆਖ਼؂ࢹ
    w τϥοΩϯάϩά
    w τϨʔεϩά
    w σʔλϕʔεϩά
    w σʔλݕূ
    (͜͜·Ͱ35෼ͳΒΑ͍ϖʔε)

    View Slide

  89. ++6($$$4QSJOHDDD@H
    ෆਖ਼௥੻ɾ؂ࢹ τϥοΩϯάϩά

    w ϩάΠϯϢʔβ*%ͱηογϣϯ͝ͱʹҰҙͳτϥοΩϯά*%Λ
    ϩάग़ྗ͢Δ
    w ϑΟϧλͱ.%$ ˞
    Ͱ࣮ݱ͢ΔػೳΛ5&3"40-6/"͕ఏڙɹ


    org.terasoluna.gfw
    terasoluna-gfw-security-web
    5.3.0.RELEASE

    ※ Mapped Diagnostic Context (Ϛοϓ͞Εͨ਍அίϯςΩετ)ɻεϨουϩʔΧϧͳMapΛ಺෦ʹ΋ͪɺΩʔ
    ʹରͯ͠஋Λput͢Ε͹remove͞ΕΔ·Ͱϩάʹputͨ͠஋Λग़ྗ͢Δ͜ͱ͕Ͱ͖Δ

    View Slide

  90. ++6($$$4QSJOHDDD@H
    w 4QSJOH4FDVSJUZͷϑΟϧλͰ.%$ʹϢʔβ*%Λઃఆ͢Δ

    // package and imports…
    import
    org.terasoluna.gfw.security.web.logging.UserIdMDCPutFilter;
    @Configuration
    public class SecurityConfig
    extends WebSecurityConfigurerAdapter {
    @Bean
    public UserIdMDCPutFilter userIdMDCPutFilter() {
    return new UserIdMDCPutFilter();
    }
    @Override
    protected void configure(HttpSecurity http)
    throws Exception {
    http.addFilterAfter(userIdMDCPutFilter(),
    AnonymousAuthenticationFilter.class);
    }
    }
    4QSJOH4FDVSJUZͷ
    "OPOZNPVT"VUIFOUJDBUJPO
    'JMUFSͷޙʹઃఆ͢Δ
    ෆਖ਼௥੻ɾ؂ࢹ τϥοΩϯάϩά

    View Slide

  91. ++6($$$4QSJOHDDD@H
    w ϑΟϧλͰ.%$ʹτϥοΩϯά*%Λઃఆ͢Δ
    w 'JMUFS࣮૷ΫϥεΛ%*ίϯςφʹొ࿥͢Ε͹ࣗಈద༻

    // package and imports…
    import org.terasoluna.gfw.web.logging.mdc.MDCClearFilter;
    import org.terasoluna.gfw.web.logging.mdc.XTrackMDCPutFilter;
    @Configuration
    public class WebConfig extends WebMvcConfigurerAdapter {
    @Bean
    MDCClearFilter mdcClearFilter() {
    return new MDCClearFilter();
    }
    @Bean
    XTrackMDCPutFilter xTrackMdcPutFilter() {
    return new XTrackMDCPutFilter();
    }
    // other settings...
    }
    એݴॱʹద༻͞ΕΔͷͰ
    .%$$MFBS'JMUFSΛઌʹએݴ͢Δ
    ෆਖ਼௥੻ɾ؂ࢹ τϥοΩϯάϩά

    View Slide

  92. ++6($$$4QSJOHDDD@H
    w l9\^zͰ.%$ͷ஋Λϩάʹग़ྗ͢Δ
    w ؆қʹઃఆ͢Δ৔߹͸BQQMJDBUJPOQSPQFSUJFTͰࢦఆ͢Δ
    w ຊ֨తʹઃఆ͢Δ৔߹͸MPHCBDLTQSJOHYNMΛ༻ҙ͢Δ

    logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS}
    %X{X-Track} %X{USER} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } ---
    [%15.15t] %-40.40logger{39} : %m%n
    2017-05-10 21:56:23.203 - INFO 85415 --- [nio-8080-exec-1] o.s.web.s
    2017-05-10 21:56:23.584 anonymousUser - INFO 85415 --- [nio-8080-exec
    2017-05-10 21:56:46.753 ca2210ef6b2a4c3cae2c2d0b8865ecfb admin - INFO
    2017-05-10 21:57:10.175 3c5815e5239f4b17bcec65b460ab0d94 admin - INFO
    2017-05-10 21:57:11.671 f68c33bed90d4193891da0291ef4e334 admin - INFO
    2017-05-10 21:57:12.230 50890f1d81b749a0b881935c2cb456a8 admin - INFO
    2017-05-10 21:57:12.407 49ca6af952684adba2654d92a57d4903 admin - INFO
    2017-05-10 22:02:07.611 261699113495481e811426a2d618eddb demo - INFO 8
    2017-05-10 22:02:10.088 11b3ce0f57a946cfae89a91ad8874b1c demo - INFO 8
    2017-05-10 22:02:12.052 567b78ca7e8547a2b986781808d155e1 admin - INFO
    ෆਖ਼௥੻ɾ؂ࢹ τϥοΩϯάϩά

    View Slide

  93. ++6($$$4QSJOHDDD@H
    ෆਖ਼௥੻ɾ؂ࢹ τϨʔεϩά

    w ίϯτϩʔϥͷݺͼग़͠։࢝ɾऴྃͱॲཧ࣌ؒΛϩάग़ྗ͢Δ
    w ΠϯλʔηϓλͰ࣮ݱ͢ΔػೳΛ5&3"40-6/"͕ఏڙ

    // package and imports...
    import
    org.terasoluna.gfw.web.logging.TraceLoggingInterceptor;
    @Configuration
    public class WebConfig extends WebMvcConfigurerAdapter {
    @Bean
    TraceLoggingInterceptor traceLoggingInterceptor() {
    return new TraceLoggingInterceptor();
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(traceLoggingInterceptor())
    .addPathPatterns("/**")
    .excludePathPatterns(“/resources/**");
    }
    }
    SFTPVSDFTΛআ͘શύεʹద༻

    View Slide

  94. ++6($$$4QSJOHDDD@H
    w ϩάϨϕϧΛUSBDFʹઃఆ

    logging.level.org.terasoluna.gfw.web.logging=trace
    2017-05-10 22:33:57.278 5bf75eb81f3847759805f8a278973d22 demo -TRACE
    87708 --- [nio-8080-exec-4] o.t.g.w.logging.TraceLoggingInterceptor :
    [START CONTROLLER] HomeController.home(Locale,LoggedInUser,Model)
    2017-05-10 22:33:57.283 5bf75eb81f3847759805f8a278973d22 demo -TRACE
    87708 --- [nio-8080-exec-4] o.t.g.w.logging.TraceLoggingInterceptor :
    [END CONTROLLER ] HomeController.home(Locale,LoggedInUser,Model)->
    view=welcome/home, model={account=Account(username=demo, password=$2a
    $10$oxSJl.keBwxmsMLkcT9lPeAIxfNTPNQxpeywMrF7A3kVszwUTqfTK,
    roles=[USER]),
    org.springframework.validation.BindingResult.account=org.springframewo
    rk.validation.BeanPropertyBindingResult: 0 errors}
    2017-05-10 22:33:57.283 5bf75eb81f3847759805f8a278973d22 demo -TRACE
    87708 --- [nio-8080-exec-4] o.t.g.w.logging.TraceLoggingInterceptor :
    [HANDLING TIME ] HomeController.home(Locale,LoggedInUser,Model)->
    4,358,195 ns
    ηΩϡΞͳ಺༰΋ग़ྗ͞ΕΔͷͰ
    औΓѻ͍ʹ͸஫ҙ͢Δ
    ෆਖ਼௥੻ɾ؂ࢹ τϨʔεϩά

    ։࢝ϩάͱऴྃϩά
    ॲཧ࣌ؒ

    View Slide

  95. ++6($$$4QSJOHDDD@H
    ෆਖ਼௥੻ɾ؂ࢹ σʔλϕʔεϩά

    w 4QSJOH%BUB+1"ʹΑΔ؂ࠪϩά
    w ొ࿥೔࣌ɺొ࿥ऀɺߋ৽೔࣌ɺߋ৽ऀΛࣗಈతʹه࿥͢Δ

    // package and imports...
    @Entity
    @EntityListeners(AuditingEntityListener.class)
    public class Account {
    // @Id, @Version...
    @CreatedDate
    private Date createdAt;
    @CreatedBy
    private String createdBy;
    @LastModifiedDate
    private Date updatedAt;
    @LastModifiedBy
    private String updatedBy;
    // getters/setters...
    }
    ΫϥεΛl!&OUJUZ-JTUFOFSzͰ
    ஫ऍͯ͠ɺl!$SFBUFEʙͱ
    z!-BTU.PEJpFEʙzͰ஫ऍͨ͠
    ϑΟʔϧυΛ௥Ճ͢Δ

    View Slide

  96. ++6($$$4QSJOHDDD@H
    w 4QSJOH4FDVSJUZͷೝূ৘ใΛऔಘ͢Δ
    // package and imports...
    @Configuration
    @EnableJpaAuditing
    public class PersistenceConfig {
    @Bean
    AuditorAware auditorProvider() {
    return new AuditorAware() {
    @Override
    public String getCurrentAuditor() {
    Authentication auth = SecurityContextHolder
    .getContext().getAuthentication();
    // return null if the user is not authenticated...
    return ((User) auth.getPrincipal()).getUsername();
    }
    };
    }
    }
    +1"؂ࠪΛ༗ޮʹ͢Δ
    4QSJOH4FDVSJUZͷೝূ৘ใ͔Β
    Ϣʔβ໊Λऔಘ͢Δ
    ෆਖ਼௥੻ɾ؂ࢹ σʔλϕʔεϩά

    View Slide

  97. ++6($$$4QSJOHDDD@H
    w σʔλొ࿥

    $ curl -X POST -u user:password \
    > -H 'Content-Type: application/json' \
    > -d '{"name":"nameA"}' http://localhost:8080/accounts/
    {
    "createdAt" : "2017-05-06T07:44:02.113+0000",
    "createdBy" : "user",
    "updatedAt" : "2017-05-06T07:44:02.113+0000",
    "updatedBy" : "user",
    "name" : “nameA",
    ...
    } ొ࿥೔࣌ɺొ࿥ऀɺߋ৽೔࣌ɺ
    ߋ৽ऀ͕ࣗಈతʹه࿥͞ΕΔ
    ෆਖ਼௥੻ɾ؂ࢹ σʔλϕʔεϩά

    View Slide

  98. ++6($$$4QSJOHDDD@H
    w σʔλߋ৽

    $ curl -X PATCH -u user:password \
    > -H 'Content-Type: application/json' \
    > -d '{"name":"nameB"}' http://localhost:8080/accounts/1
    {
    "createdAt" : "2017-05-06T07:44:02.113+0000",
    "createdBy" : "user",
    "updatedAt" : "2017-05-06T08:07:53.632+0000",
    "updatedBy" : "user",
    "name" : “nameB",
    ...
    } ߋ৽೔࣌ɺߋ৽ऀ͕ࣗಈతʹ
    ه࿥͞ΕΔ
    ෆਖ਼௥੻ɾ؂ࢹ σʔλϕʔεϩά

    View Slide

  99. ++6($$$4QSJOHDDD@H
    w ਌Ϋϥεʹू໿͢Δͱศར

    // package and imports...
    @MappedSuperclass
    @EntityListeners(AuditingEntityListener.class)
    public abstract class AbstractEntity {
    // @Id, @Version...
    @CreatedDate protected Date createdAt;
    @CreatedBy protected String createdBy;
    @LastModifiedDate protected Date updatedAt;
    @LastModifiedBy protected String updatedBy;
    // getters/setters...
    }
    // package and imports...
    @Entity
    public class Account extends AbstractEntity {
    // other fields, getters/setters...
    }
    ΤϯςΟςΟͷ਌Ϋϥε͸
    l!.BQQFE4VQFSDMBTTzͰ஫ऍ͢Δ
    ΤϯςΟςΟ͸਌ΫϥεΛܧঝ͢Δ
    ෆਖ਼௥੻ɾ؂ࢹ σʔλϕʔεϩά

    View Slide

  100. ++6($$$4QSJOHDDD@H
    4QSJOH4FDVSJUZ0UIFST
    w 8FCରࡦ

    େ߲໨ த߲໨
    Մ༻ੑ ܧଓੑɺ଱ো֐ੑɺࡂ֐ରࡦɺճ෮ੑ
    ੑೳɾ֦ுੑ ۀ຿ॲཧྔɺੑೳ໨ඪ஋ɺϦιʔε֦ுੑɺੑೳ඼࣭อূ
    ӡ༻ɾอकੑ
    ௨ৗӡ༻ɺอकӡ༻ɺো֐࣌ӡ༻ɺӡ༻؀ڥɺαϙʔτମ੍ɺͦͷଞӡ༻
    ؅ཧํ਑
    Ҡߦੑ Ҡߦ࣌ظɺҠߦํࣜɺҠߦର৅ʢػثʣɺҠߦର৅ʢσʔλʣɺҠߦܭը
    ηΩϡϦςΟ
    લఏ৚݅ɾ੍໿৚݅ɺηΩϡϦςΟϦεΫରԠɺηΩϡϦςΟ਍அɺ
    ηΩϡϦςΟϦεΫ؅ཧɺΞΫηεɾར༻੍ݶɺσʔλͷൿಗɺ
    ෆਖ਼௥੻ɾ؂ࢹɺωοτϫʔΫରࡦɺϚϧ΢ΣΞରࡦɺWebରࡦ
    ؀ڥɾ
    Τίϩδʔ
    γεςϜ੍໿/લఏ৚݅ɺγεςϜಛੑɺద߹ن֨ɺػࡐઃஔ؀ڥ৚݅ɺ
    ؀ڥϚωδϝϯτ
    w 8FC࣮૷ରࡦ
    w ηογϣϯ؅ཧ
    w 944ରࡦ
    w $43'ରࡦ
    w ηΩϡϦςΟϔομ
    Spring Security
    & Others
    (͜͜·Ͱ40෼ͳΒΑ͍ϖʔε)

    View Slide

  101. ++6($$$4QSJOHDDD@H
    8FCରࡦ ηογϣϯ؅ཧ

    w ηογϣϯݻఆ߈ܸରࡦ

    c
    c
    ϩάΠϯʹ੒ޭ͢Δͱ৽͍͠
    ηογϣϯ*%͕෷͍ग़͞ΕΔ

    View Slide

  102. ++6($$$4QSJOHDDD@H
    8FCରࡦ 944ରࡦ

    w 5IZNFMFBG͸σϑΥϧτͰಛघจࣈΛΤεέʔϓ͢Δ
    w SBXͰग़ྗ͍ͨ͠৔߹͸lUIVUFYU\^zͰ໌ࣔ͢Δ

    // (snip)
    @GetMapping("xss")
    String xss(Model model) {
    model.addAttribute(“script",
    "alert('Hello, Xss!');");
    model.addAttribute(“marquee",
    "Hello, Xss!");
    return "xss";
    // (snip)

    xss



    View Slide

  103. ++6($$$4QSJOHDDD@H
    8FCରࡦ 944ରࡦ


    c
    c

    View Slide

  104. ++6($$$4QSJOHDDD@H
    8FCରࡦ $43'ରࡦ

    w σϑΥϧτͰ$43'τʔΫϯ͕IJEEFOʹग़ྗ͞ΕΔ

    c

    View Slide

  105. ++6($$$4QSJOHDDD@H
    8FCରࡦ $43'ରࡦ

    w 4QSJOH4FDVSJUZ͔Β$PPLJFʹอଘ͢Δ͜ͱ΋Ͱ͖Δ

    // package and imports...
    @Configuration
    public class SecurityConfig extends
    WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http)
    throws Exception {
    http.csrf().csrfTokenRepository(
    new CookieCsrfTokenRepository())
    }
    }
    "OHVMBSͷ࢓༷ʹ߹Θͤͯ
    l943'50,&/zͷ໊લͰग़ྗ

    View Slide

  106. ++6($$$4QSJOHDDD@H
    8FCରࡦ ηΩϡϦςΟϔομ

    w σϑΥϧτͰଟ਺ͷηΩϡϦςΟϔομ͕ઃఆ͞ΕΔ

    c
    c
    c

    View Slide

  107. ++6($$$4QSJOHDDD@H
    4QSJOH4FDVSJUZ0UIFST·ͱΊ
    w ΞΫηεɾར༻੍ݶ
    w 4QSJOH4FDVSJUZ 1BTTBZ 5&3"40-6/"
    w σʔλͷൿಗ
    w 4QSJOH4FDVSJUZ KBTZQU
    w ෆਖ਼௥੻ɾ؂ࢹ
    w 4QSJOH4FDVSJUZ +1" 5&3"40-6/"
    w 8FCରࡦ
    w 4QSJOH4FDVSJUZ 5IZNFMFBG

    View Slide

  108. ++6($$$4QSJOHDDD@H
    ·ͱΊ

    View Slide

  109. ++6($$$4QSJOHDDD@H
    ·ͱΊ
    w ඇػೳཁ݅ͱ͸
    w ඇػೳཁٻάϨʔυΛ׆༻͢Δ
    w lૣظʹzlޡղͳ͘zl࿙Βͣ͞ʹzఆٛ͢Δ
    w 4QSJOH#PPU"DUVBUPS
    w ؆୯Πϯετʔϧɺߴ͍ΧελϚΠζੑͱ֦ுੑ
    w ӡ༻ɾอक͸΋ͪΖΜɺ։ൃʹ΋༗༻
    w 4QSJOH4FDVSJUZ0UIFST
    w 4QSJOH4FDVSJUZΛத৺ͱͨ͠ϥΠϒϥϦ܈Λ׆༻͢Δ

    View Slide

  110. ++6($$$4QSJOHDDD@H
    5IBOLZPV


    View Slide