Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

++6($$$4QSJOHDDD@H ࣗݾ঺հ w കᖒ༤Ұ࿠ ͏Ί͟ΘΏ͏͍ͪΖ͏ w ͕Δ͕΂ !HBSCBHFUPXO w גࣜձࣾ%54 w 4*FS w ೥݄ೖࣾ w ೥݄ҟಈ w डୗ։ൃˠݚڀ։ൃɾٕज़ࢧԉ w ՝֎׆ಈ w 1MBZ'SBNFXPSLؔ࿈ͰدߘɺొஃͳͲ w ͨ·ʹυϥϜΛୟ͘

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

++6($$$4QSJOHDDD@H ඇػೳཁ݅ͱ͸ http://cloudeo.jp/word/glossary/function_nonfunction.html

Slide 7

Slide 7 text

++6($$$4QSJOHDDD@H ඇػೳཁ݅ͱ͸ http://cloudeo.jp/word/glossary/function_nonfunction.html

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

++6($$$4QSJOHDDD@H ඇػೳཁٻάϨʔυ https://www.ipa.go.jp/files/000005076.pdf

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

++6($$$4QSJOHDDD@H ඇػೳཁٻάϨʔυ w ϞσϧγεςϜΛબΜͰ֤߲໨ͷϨϕϧΛௐઅ͢Δ w ྫ ࣗಈंͷߪೖΛߟ͑Δ w ར༻࣌ؒˠฏ೔னؒ ʙ ͸ར༻͠ͳ͍ w ࠷ߴ଎౓ˠLNI ۓٸ࣌ͷΈLNI w ৐ंఆһˠਓ w αϙʔτɾΞϑλʔέΞˠֹ݄̋ઍԁͷอݥʹՃೖ w ౪೉ରࡦˠ԰಺றं৔ʴϋϯυϧϩοΫ w ೩අˠLNὙҎ্ w FUDˠͦͷଞʹݕ౼͢΂͖ࣄ߲͸ʁ අ༻ରޮՌΛ۩ମతʹ Πϝʔδܾͯ͠ఆͨ͠ཁٻ

Slide 26

Slide 26 text

++6($$$4QSJOHDDD@H ඇػೳཁٻάϨʔυ w ϞσϧγεςϜΛબΜͰ֤߲໨ͷϨϕϧΛௐઅ͢Δ w ྫ ࣗಈंͷߪೖΛߟ͑Δ w ར༻࣌ؒˠฏ೔னؒ ʙ ͸ར༻͠ͳ͍ w ࠷ߴ଎౓ˠLNI ۓٸ࣌ͷΈLNI w ৐ंఆһˠਓ w αϙʔτɾΞϑλʔέΞˠֹ݄̋ઍԁͷอݥʹՃೖ w ౪೉ରࡦˠ԰಺றं৔ʴϋϯυϧϩοΫ w ೩අˠLNὙҎ্ w ೩ྉλϯΫ༰ྔˠὙҎ্ w ഉؾྔˠ DDʙ DD ౰ॳ͸ݕ౼͔Β࿙Ε͍ͯͨ ߲໨

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

++6($$$4QSJOHDDD@H Spring Boot Actuator (͜͜·Ͱ10෼ͳΒΑ͍ϖʔε)

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

++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 ΤϯυϙΠϯτ͕ ଟ਺௥Ճ͞ΕΔ

Slide 36

Slide 36 text

++6($$$4QSJOHDDD@H 4QSJOH#PPU"DUVBUPSͱ͸ ௥Ճ͞ΕͨΤϯυϙΠϯτʹ )551ͰΞΫηε͢Δͱ ֤छ৘ใΛ+40/ͰऔಘͰ͖Δ

Slide 37

Slide 37 text

++6($$$4QSJOHDDD@H 4QSJOH#PPU"DUVBUPSͱ͸ +40/7JFXϓϥάΠϯͳͲͰ ੔ܗͯ͠ݕࡧ͢Δͱݟқ͍

Slide 38

Slide 38 text

++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Ͱ੔ܗɺ ϑΟϧλͯ͠΋ྑ͍

Slide 39

Slide 39 text

++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

Slide 40

Slide 40 text

++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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

++6($$$4QSJOHDDD@H &OEQPJOUT ຊηογϣϯͷઆ໌ର৅

Slide 43

Slide 43 text

++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" } }

Slide 44

Slide 44 text

++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`Ϣʔβ͕ Ҏ߱ʹ ೝূࣦഊͨ͠ΠϕϯτΛநग़

Slide 45

Slide 45 text

++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ͷΈදࣔ͞ΕΔ

Slide 46

Slide 46 text

++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" }

Slide 47

Slide 47 text

++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" } ΞϓϦέʔγϣϯͷϒϥϯν΍ ίϛοτ*%͕දࣔ͞ΕΔ

Slide 48

Slide 48 text

++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 ΞϓϦέʔγϣϯͷόʔδϣϯ΍ Ϗϧυ͕ͨ࣌ؒ͠දࣔ͞ΕΔ

Slide 49

Slide 49 text

++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

Slide 50

Slide 50 text

++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͢Δ

Slide 51

Slide 51 text

++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, ... }

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

++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" } } } }

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

++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Λ࣮૷͢Δ μϛʔͷ࣮૷ྫɻ ࣮ࡍ͸%*ίϯςφ΍σʔλϕʔε ͔Β஋Λऔಘͯ͠ฦ͢

Slide 56

Slide 56 text

++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 ...

Slide 57

Slide 57 text

++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Λ ܧঝ͢Δ

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

++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 Λ࡞ͬͯฦ͢

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

++6($$$4QSJOHDDD@H 4QSJOH4FDVSJUZ 0UIFST (͜͜·Ͱ25෼ͳΒΑ͍ϖʔε) (ਫΛҿΉ)

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

++6($$$4QSJOHDDD@H ΞΫηεɾར༻੍ݶ ύεϫʔυϙϦγʔ w lจࣈҎ্ɺେখ਺ࣈΛͦΕͧΕจࣈҎ্zΈ͍ͨͳΞϨ http://www.passay.org/

Slide 67

Slide 67 text

++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Ͱ ࣮૷͢Δ

Slide 68

Slide 68 text

++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) } จࣈҎ্ɺ େจࣈɺখจࣈɺ਺ࣈ ͦΕͧΕจࣈҎ্

Slide 69

Slide 69 text

++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Ͱೖྗ஋ͷଥ౰ੑΛ ݕূ͢Δ

Slide 70

Slide 70 text

++6($$$4QSJOHDDD@H ΞΫηεɾར༻੍ݶ ύεϫʔυϙϦγʔ w εΫϦʔϯγϣοτషΔ

Slide 71

Slide 71 text

++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

Slide 72

Slide 72 text

++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... }

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

++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); }

Slide 76

Slide 76 text

++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Ͱ஫ऍͯ͠ Ҿ਺ʹࢦఆͨ͠ܕͷΠϕϯτΛ ϋϯυϦϯά͢Δ ೝূࣦഊճ਺Λ ΠϯΫϦϝϯτͯ͠ อଘ͢Δ

Slide 77

Slide 77 text

++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 ͱΞΧ΢ϯτϩοΫঢ়ଶΛ ड͚Δ

Slide 78

Slide 78 text

++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); } } ೝূࣦഊճ਺্͕ݶΛ௒͍͑ͯΔ͔ ൑ఆͯ͠ίϯετϥΫλʹ౉͢

Slide 79

Slide 79 text

++6($$$4QSJOHDDD@H ΞΫηεɾར༻੍ݶ ΞΧ΢ϯτϩοΫ ΞΧ΢ϯτϩοΫঢ়ଶͷ৔߹͸ ύεϫʔυ͕ਖ਼ͯ͘͠΋ೝূʹ ࣦഊ͢Δ ύεϫʔυ࿈ଓࣦഊճ਺্ݶʹ ຬͨͳ͍৔߹

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

++6($$$4QSJOHDDD@H w 4)"Ͱͳ͘#DSZQU·ͨ͸4DSZQUΛ࢖͏΂͖ w ฏจ͸࿦֎ɺ.%ɺ4)"͸ίϦδϣϯ͕ݟ͔͍ͭͬͯΔ w ͦͷଞͷ4)"΋ڧ౓ΑΓ଎౓༏ઌ https://rietta.com/blog/2016/02/05/bcrypt-not-sha-for-passwords/ σʔλͷൿಗ ύεϫʔυͷϋογϡԽ

Slide 82

Slide 82 text

++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... }

Slide 83

Slide 83 text

++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); } } ฏจύεϫʔυͱͷಥ߹΍ϋογϡԽ

Slide 84

Slide 84 text

++6($$$4QSJOHDDD@H σʔλͷൿಗ ػີ৘ใͷ҉߸Խ w ֤छ઀ଓ৘ใͳͲΛ ϋογϡԽͰ͸ͳ͘ ҉߸Խ͢Δ http://www.jasypt.org/

Slide 85

Slide 85 text

++6($$$4QSJOHDDD@H σʔλͷൿಗ ػີ৘ใͷ҉߸Խ w KBTZQUTQSJOHCPPUTUBSUFS͕ఏڙ͞Ε͍ͯΔ https://github.com/ulisesbocchio/jasypt-spring-boot

Slide 86

Slide 86 text

++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== ಘΒΕͨ҉߸ )ͷ઀ଓϢʔβ໊Λ҉߸Խ͢Δྫɻ ҉߸Խ͢Δ஋ɺ伴ɺΞϧΰϦζϜΛ ࢦఆͯ͠҉߸ԽॲཧΛ࣮ߦ

Slide 87

Slide 87 text

++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ͰғΜͰෳ߹ର৅Ͱ ͋Δ͜ͱΛࣔ͢ 伴Λ௚઀ઃఆ͢ΔͱηΩϡϦςΟڧ౓తʹ ͋·Γҙຯ͕ͳ͍ ؀ڥม਺ͳͲ͔ΒಡΈࠐΜͰࢦఆ͢Δ

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

++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ͨ͠஋Λग़ྗ͢Δ͜ͱ͕Ͱ͖Δ

Slide 90

Slide 90 text

++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ͷޙʹઃఆ͢Δ ෆਖ਼௥੻ɾ؂ࢹ τϥοΩϯάϩά

Slide 91

Slide 91 text

++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Λઌʹએݴ͢Δ ෆਖ਼௥੻ɾ؂ࢹ τϥοΩϯάϩά

Slide 92

Slide 92 text

++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 ෆਖ਼௥੻ɾ؂ࢹ τϥοΩϯάϩά

Slide 93

Slide 93 text

++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Λআ͘શύεʹద༻

Slide 94

Slide 94 text

++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 ηΩϡΞͳ಺༰΋ग़ྗ͞ΕΔͷͰ औΓѻ͍ʹ͸஫ҙ͢Δ ෆਖ਼௥੻ɾ؂ࢹ τϨʔεϩά ։࢝ϩάͱऴྃϩά ॲཧ࣌ؒ

Slide 95

Slide 95 text

++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Ͱ஫ऍͨ͠ ϑΟʔϧυΛ௥Ճ͢Δ

Slide 96

Slide 96 text

++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ͷೝূ৘ใ͔Β Ϣʔβ໊Λऔಘ͢Δ ෆਖ਼௥੻ɾ؂ࢹ σʔλϕʔεϩά

Slide 97

Slide 97 text

++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", ... } ొ࿥೔࣌ɺొ࿥ऀɺߋ৽೔࣌ɺ ߋ৽ऀ͕ࣗಈతʹه࿥͞ΕΔ ෆਖ਼௥੻ɾ؂ࢹ σʔλϕʔεϩά

Slide 98

Slide 98 text

++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", ... } ߋ৽೔࣌ɺߋ৽ऀ͕ࣗಈతʹ ه࿥͞ΕΔ ෆਖ਼௥੻ɾ؂ࢹ σʔλϕʔεϩά

Slide 99

Slide 99 text

++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Ͱ஫ऍ͢Δ ΤϯςΟςΟ͸਌ΫϥεΛܧঝ͢Δ ෆਖ਼௥੻ɾ؂ࢹ σʔλϕʔεϩά

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

++6($$$4QSJOHDDD@H 8FCରࡦ ηογϣϯ؅ཧ w ηογϣϯݻఆ߈ܸରࡦ c c ϩάΠϯʹ੒ޭ͢Δͱ৽͍͠ ηογϣϯ*%͕෷͍ग़͞ΕΔ

Slide 102

Slide 102 text

++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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

++6($$$4QSJOHDDD@H 8FCରࡦ $43'ରࡦ w σϑΥϧτͰ$43'τʔΫϯ͕IJEEFOʹग़ྗ͞ΕΔ c

Slide 105

Slide 105 text

++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ͷ໊લͰग़ྗ

Slide 106

Slide 106 text

++6($$$4QSJOHDDD@H 8FCରࡦ ηΩϡϦςΟϔομ w σϑΥϧτͰଟ਺ͷηΩϡϦςΟϔομ͕ઃఆ͞ΕΔ c c c

Slide 107

Slide 107 text

++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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

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

Slide 110

Slide 110 text

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