Slide 1

Slide 1 text

4QSJOH'FTUTG@KTVH ίΠχʔגࣜձࣾɹ಺ཱྑհʢ!CBJEʣ "NB[PO$PHOJUP࢖ͬͯೝূ͍ͨ͠ʁ ͦΕͳΒ4QSJOH4FDVSJUZ࢖͍·͠ΐ͏ʂ

Slide 2

Slide 2 text

ࣗݾ঺հ w ໊લ w ಺ཱྑհʢ͏ͪͨͯΓΐ͏͚͢ʣ w झຯ w ༸෰ w ύϯ԰८Γ w ॴଐ w ίΠχʔגࣜձࣾ w ++6( w 'BTIJPO$IBSJUZ1SPKFDU w 5XJUUFS w !CBJEQT

Slide 3

Slide 3 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 4

Slide 4 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 5

Slide 5 text

શମਤ

Slide 6

Slide 6 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 7

Slide 7 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ " 4QSJOH4FDVSJUZ֓ཁ # ೝূॲཧͷ࢓૊Έ $ ೝՄॲཧͷ࢓૊Έ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 8

Slide 8 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ " 4QSJOH4FDVSJUZ֓ཁ # ೝূॲཧͷ࢓૊Έ $ ೝՄॲཧͷ࢓૊Έ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 9

Slide 9 text

ొ৔͢ΔओͳϞδϡʔϧ܈ $PSF ೝূͱೝՄػೳ 8FC 8FCΞϓϦͷ ηΩϡϦςΟରࡦ $POpH 9.-ωʔϜεϖʔεɺ +BWB$POpHΛαϙʔτ

Slide 10

Slide 10 text

ϑϨʔϜϫʔΫͷΞʔΩςΫνϟ

Slide 11

Slide 11 text

ϑϨʔϜϫʔΫͷΞʔΩςΫνϟ

Slide 12

Slide 12 text

ओͳ4FDVSJUZ'JMUFS w -PHPVU'JMUFS w ϩάΞ΢τॲཧΛߦ͏ɻ w "OPOZNPVT"VUIFOUJDBUJPO'JMUFS w ಗ໊Ϣʔβೝূͱͯ͠ೝূ͢Δɻ w #BTJD"VUIFOUJDBUJPO'JMUFS w #BTJDೝূΛߦ͏ࡍʹ࢖͏ɻ

Slide 13

Slide 13 text

4FDVSJUZ'JMUFSͷॱং final class FilterComparator implements Comparator, Serializable { private static final int INITIAL_ORDER = 100; private static final int ORDER_STEP = 100; private final Map filterToOrder = new HashMap<>(); FilterComparator() { Step order = new FilterComparator.Step(INITIAL_ORDER, ORDER_STEP); put(ChannelProcessingFilter.class, order.next()); put(ConcurrentSessionFilter.class, order.next()); put(WebAsyncManagerIntegrationFilter.class, order.next()); put(SecurityContextPersistenceFilter.class, order.next()); put(HeaderWriterFilter.class, order.next()); put(CorsFilter.class, order.next()); put(CsrfFilter.class, order.next()); put(LogoutFilter.class, order.next()); // …… 'JMUFS$PNQBSBUPSKBWB

Slide 14

Slide 14 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ " 4QSJOH4FDVSJUZ֓ཁ # ೝূॲཧͷ࢓૊Έ $ ೝՄॲཧͷ࢓૊Έ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 15

Slide 15 text

ೝূ "VUIFOUJDBUJPO w ର৅͕୭ʢԿʣͰ͋Δ͔Λ֬ೝ͢Δ͜ͱɻ w ຊਓೝূʹ༻͍ΒΕΔ৘ใ͸ݻ༗৘ใͰͳ͚ Ε͹ͳΒͳ͍ɻ

Slide 16

Slide 16 text

ೝূͷཁૉ આ໌ ݻ༗৘ใ ੜମ৘ใ ੜ෺ݻ༗ͷ৘ใɾಛੑ ࢦ໲ɺ੩຺ɺ إɺ੠໲ ஌ࣝ৘ใ ຊਓ͔͠ ஌Βͳ͍৘ใ ʢϫϯλΠϜʣύεϫʔυɺ ൿີͷ࣭໰ ॴ࣋৘ใ ຊਓ͔࣋ͬͯ͠ͳ͍ ৘ใ΍෺ *$Χʔυɺ ϋʔυ΢ΣΞτʔΫϯ

Slide 17

Slide 17 text

ೝূॲཧͷ࢓૊Έ

Slide 18

Slide 18 text

ೝূॲཧͷ࢓૊Έ

Slide 19

Slide 19 text

ೝূॲཧͷ࢓૊Έ

Slide 20

Slide 20 text

ʹΜ͠ΐ͏͠ΐΓͷ͘͠Έ

Slide 21

Slide 21 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ " 4QSJOH4FDVSJUZ֓ཁ # ೝূॲཧͷ࢓૊Έ $ ೝՄॲཧͷ࢓૊Έ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 22

Slide 22 text

ೝՄ "VUIPSJ[BUJPO w ͋Δಛఆͷ৚݅ʹରͯ͠ɺΞΫηεݖݶΛ༩͑ Δ͜ͱɻ

Slide 23

Slide 23 text

ೝՄॲཧͷ࢓૊Έ

Slide 24

Slide 24 text

ೝՄॲཧͷ࢓૊Έ

Slide 25

Slide 25 text

ೝՄॲཧͷ࢓૊Έ

Slide 26

Slide 26 text

"DDFTT%FDJTJPO7PUFSKBWB w ΞΫηεݖͷ෇༩͢Δ͔Λ౤ථ͢Δɻ w 8FC&YQSFTTJPO7PUFSKBWB͕σϑΥϧτద༻ɻ public interface AccessDecisionVoter { int ACCESS_GRANTED = 1; int ACCESS_ABSTAIN = 0; int ACCESS_DENIED = -1; (3"/5&%ɿࢍ੒ "#45"*/ɿغ٫ʢ࣍ͷ7PUFS΁ʣ %&/*&%ɿڋ൱

Slide 27

Slide 27 text

"DDFTT%FDJTJPO.BOBHFSKBWB w ౤ථ݁Ռ͔Β࠷ऴతͳΞΫηεݖΛ൑அɻ w "DDFTT%FDJTJPO7PUFSΛݺΜͰΞΫηεݖΛ౤ ථͯ͠΋Β͏ɻ ࣮૷Ϋϥε "GpSNBUJWF#BTFEKBWB $POTFOTVT#BTFEKBWB 6OBOJNPVT#BTFEKBWB

Slide 28

Slide 28 text

"GpSNBUJWF#BTFEKBWB w ෳ਺͋Δ7PUFSͷ͏ͪ̍ͭͰ΋ࢍ੒͢Ε͹ΞΫ ηεڐՄ͢Δɻ

Slide 29

Slide 29 text

$POTFOTVT#BTFEKBWB w 7PUFSͷࢍ੒ථͱ൓ରථͷଟ͍ํʹै͏ɻ

Slide 30

Slide 30 text

6OBOJNPVT#BTFEKBWB w 7PUFSͷ͏ͪͭͰ΋൓ର͢Ε͹ΞΫηεΛڋ ൱͢Δɻ

Slide 31

Slide 31 text

ʹΜ͔͠ΐΓͷ͘͠Έ ౤ථ݁Ռͷѻ͍ํΛܾΊΔ ౤ථ͢Δ

Slide 32

Slide 32 text

ͲΜͳͱ͖ʹ7PUFS࣮૷͢Δʁ

Slide 33

Slide 33 text

͜Μͳͱ͖ʹ7PUFS࣮૷ͯ͠Έͯ͸ʁ w ࣌͸ಛఆͷ3PMFͷϢʔβ͸ΞΫηεෆՄ w ࡀҎ্͸ΞΫηεෆՄ

Slide 34

Slide 34 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 35

Slide 35 text

$PHOJUPೝূ࡞Δલͷ͏ͪͨͯͷϨϕϧ w "VUIFOUJDBUJPŐ̋ͱ͔̋̋'JMUFSଟ͘ͳ͍ʁ w Ϋϥε໊΍ͨΒ௕͍ w 4QSJOH4FDVSJUZͬͯෳࡶͳΠϝʔδ w ೝূɾೝՄͬͯͲ͏͍͏ྲྀΕͰߦΘΕΕΔʁ εϓϦϯάηΩϡϦςΟίϫΠ

Slide 36

Slide 36 text

جຊͷ'03.ೝূ͔Β ݟͯΈΔ͔ʂ

Slide 37

Slide 37 text

ϩάΠϯϑΥʔϜ

Slide 38

Slide 38 text

ϑΥʔϜೝূͷྲྀΕ

Slide 39

Slide 39 text

࣮૷͢ΔΫϥε w 8FC4FDVSJUZ$POpHKBWB w 4QSJOH4FDVSJUZ༻ͷઃఆ w 6TFS%FUBJMT4FSWJDF*NQMKBWB w 6TFS%FUBJMT4FSWJDFΠϯλʔϑΣʔεͷ࣮૷ɻࢿ֨৘ใͱϢʔβͷঢ়ଶΛ σʔλετΞ͔Βऔಘ

Slide 40

Slide 40 text

8FC4FDVSJUZ$POpHKBWB @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private final UserDetailsServiceImpl userDetailsService; // …… @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/js/**", "/css/**", "/webjars/**").permitAll() .antMatchers("/users/**").hasRole(Role.STAFF.name()) .antMatchers("/**").authenticated() .and() .formLogin() .loginPage("/login") .loginProcessingUrl("/login") .defaultSuccessUrl("/success", true) .failureUrl("/login?error=true").permitAll(); } }

Slide 41

Slide 41 text

8FC4FDVSJUZ$POpHKBWB @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private final UserDetailsServiceImpl userDetailsService; // …… @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/js/**", "/css/**", "/webjars/**").permitAll() .antMatchers("/users/**").hasRole(Role.STAFF.name()) .antMatchers("/**").authenticated() .and() .formLogin() .loginPage("/login") .loginProcessingUrl("/login") .defaultSuccessUrl("/success", true) .failureUrl("/login?error=true").permitAll(); } } ୭Ͱ΋ΞΫηεՄ KT DTT XFCKBST 45"''ϩʔϧͷΈΞΫηεՄ VTFST ೝূϢʔβͷΈΞΫηεՄ '03.ೝূͷઃఆ ϩά ΠϯϖʔδɿMPHJO ࢿ֨৘ใ1045ઌɿMPHJO ೝূ੒ޭޙͷϦμΠϨΫτઌɿTVDDFTF ೝূࣦഊޙͷϦμΠϨΫτઌɿMPHJO FSSPSUSVF

Slide 42

Slide 42 text

'PSN-PHJO$POpHVSFSKBWB public FormLoginConfigurer() { super(new UsernamePasswordAuthenticationFilter(),null); usernameParameter("username"); passwordParameter("password"); } '03.ϩάΠϯͷઃఆΛߦ͏ɻ

Slide 43

Slide 43 text

ϩάΠϯϘλϯΛ ԡͨ͠ޙͷྲྀΕ

Slide 44

Slide 44 text

"VUIFOUJDBUJPO'JMUFSKBWBͰೝূ

Slide 45

Slide 45 text

6TFSOBNF1BTTXPSE"VUIFOUJDBUJPO'JMUFSBUUFNQU"VUIFOUJDBUJPO public Authentication attemptAuthentication( HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { // …… String username = obtainUsername(request); String password = obtainPassword(request); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); }

Slide 46

Slide 46 text

6TFSOBNF1BTTXPSE"VUIFOUJDBUJPO'JMUFSBUUFNQU"VUIFOUJDBUJPO public Authentication attemptAuthentication( HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { // …… String username = obtainUsername(request); String password = obtainPassword(request); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); }

Slide 47

Slide 47 text

1SPWJEFS.BOBHFSKBWBʹҕৡ

Slide 48

Slide 48 text

1SPWJEFS.BOBHFSBVUIFOUJDBUF public Authentication authenticate(Authentication authentication) throws AuthenticationException { // …… for (AuthenticationProvider provider : getProviders()) { if (!provider.supports(toTest)) { continue; } // …… try { result = provider.authenticate(authentication); if (result != null) { copyDetails(authentication, result); break; } } // ……

Slide 49

Slide 49 text

ೝূॲཧΛߦ͏

Slide 50

Slide 50 text

%BP"VUIFOUJDBUJPO1SPWJEFSSFUSJFWF6TFS protected final UserDetails retrieveUser( String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { // …… try { UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username); if (loadedUser == null) { // …… } return loadedUser; } // …… } Ϣʔβ৘ใΛऔಘ

Slide 51

Slide 51 text

6TFS%FUBJMT4FSWJDF*NQMKBWB @Service @RequiredArgsConstructor public class UserDetailsServiceImpl implements UserDetailsService { private final UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username) .orElseThrow( () -> new UsernameNotFoundException("username not found")); return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), createAuthorityList("ROLE_" + user.getRole().name())); } } ࢿ֨৘ใͱϢʔβͷঢ়ଶΛσʔλετΞ͔Βऔಘ͢Δ

Slide 52

Slide 52 text

%BP"VUIFOUJDBUJPO1SPWJEFSBEEJUJPOBM"VUIFOUJDBUJPO$IFDLT protected void additionalAuthenticationChecks( UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { // …… String presentedPassword = authentication.getCredentials().toString(); if (!passwordEncoder.matches( presentedPassword, userDetails.getPassword())) { // …… throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } } ύεϫʔυͷൺֱ

Slide 53

Slide 53 text

ೝূ੒ޭͱࣦഊ

Slide 54

Slide 54 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 55

Slide 55 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP BܦҢ C"NB[PO$PHOJUPͱ͸ʁ $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 56

Slide 56 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP BܦҢ C"NB[PO$PHOJUPͱ͸ʁ $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 57

Slide 57 text

ܦҢ

Slide 58

Slide 58 text

ܦҢ

Slide 59

Slide 59 text

ܦҢ $PHOJUPΛ࢖ͬͯΈΔ͔ʂ

Slide 60

Slide 60 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP BܦҢ C"NB[PO$PHOJUPͱ͸ʁ $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 61

Slide 61 text

"NB[PO$PHOJUPͱ͸ʁ w 8FC΍ϞόΠϧΞϓϦͷೝূɾೝՄɺϢʔβ ؅ཧΛαϙʔτ w ௚઀͔αʔυύʔςΟΛ௨ͯ͡αΠϯΠϯ w ओͳίϯϙʔωϯτ͸Ϣʔβϓʔϧͱ*%ϓʔϧ w 40$ 1$*%44 *40ͳͲʹ४ڌ ࠓճ͸Ϣʔβϓʔϧͷ࿩ͷΈ

Slide 62

Slide 62 text

Ϣʔβϓʔϧ w "NB[PO$PHOJUPͷϢʔβσΟϨΫτϦ w 8FC·ͨ͸ϞόΠϧΞϓϦʹϩά ΠϯͰ͖Δ w αΠϯΞοϓ͓ΑͼαΠϯΠϯ w ೝূ੒ޭޙʹϢʔβϓʔϧτʔΫϯ͕ฦΔ ϢʔβϓʔϧτʔΫϯ *%τʔΫϯ ΞΫηετʔΫϯ ߋ৽τʔΫϯ

Slide 63

Slide 63 text

ΞΫηετʔΫϯ w ೝূ͞ΕͨϢʔβʹؔ͢ΔΫϨʔϜؚ͕·Ε ͍ͯΔɻ w +40/8FCτʔΫϯ +85 Ͱ͋Δɻ w ༗ޮظݶ͸࣌ؒ

Slide 64

Slide 64 text

$PHJOJUP"1*Ͱͷೝূ࣌ͷొ৔ਓ෺ w ೝূλΠϓʢBVUI5ZQFʣ w ηογϣϯʢTFTTJPOʣ w ΞΫηετʔΫϯʢBDDFTT5PLFOʣ w ϦϑϨογϡτʔΫϯʢSFGSTI5PLFOʣ w *%τʔΫϯʢJE5PLFOʣ ࠓճ͸࢖Θͳ͍ ࠓճ͸࢖Θͳ͍

Slide 65

Slide 65 text

αΠϯΞοϓ͔ΒαΠϯΠϯ

Slide 66

Slide 66 text

αΠϯΞοϓ͔ΒαΠϯΠϯ

Slide 67

Slide 67 text

αΠϯΞοϓ͔ΒαΠϯΠϯ

Slide 68

Slide 68 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 69

Slide 69 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ B*%ɺύεϫʔυೝূ CΞΫηετʔΫϯೝূ 4QSJOH4FDVSJUZͷςετ

Slide 70

Slide 70 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ B*%ɺύεϫʔυೝূ CΞΫηετʔΫϯೝূ 4QSJOH4FDVSJUZͷςετ

Slide 71

Slide 71 text

*%ɺύεϫʔυೝূ *%ͱύεϫʔυ͕ਖ਼͚͠Ε͹τʔΫϯΛฦ͢ɻ

Slide 72

Slide 72 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ B*%ɺύεϫʔυೝূ CΞΫηετʔΫϯೝূ 4QSJOH4FDVSJUZͷςετ

Slide 73

Slide 73 text

ΞΫηετʔΫϯೝূ

Slide 74

Slide 74 text

͋ͤ͘͢ͱʔ͘ΜʹΜ͠ΐ͏

Slide 75

Slide 75 text

$VTUPN1SF"VUIFOUJDBUFE1SPDFTTJOH'JMUFSKBWB public class CustomPreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter { @Override protected Object getPreAuthenticatedPrincipal( HttpServletRequest request) { return ""; } @Override protected Object getPreAuthenticatedCredentials( HttpServletRequest request) { String accessToken = request.getHeader(HttpHeaders.AUTHORIZATION); if (StringUtils.isEmpty(accessToken) || !accessToken.startsWith("Bearer ")) { return ""; } return accessToken.split(" ")[1]; } }

Slide 76

Slide 76 text

$VTUPN1SF"VUIFOUJDBUFE1SPDFTTJOH'JMUFSKBWB public class CustomPreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter { @Override protected Object getPreAuthenticatedPrincipal( HttpServletRequest request) { return ""; } @Override protected Object getPreAuthenticatedCredentials( HttpServletRequest request) { String accessToken = request.getHeader(HttpHeaders.AUTHORIZATION); if (StringUtils.isEmpty(accessToken) || !accessToken.startsWith("Bearer ")) { return ""; } return accessToken.split(" ")[1]; } }

Slide 77

Slide 77 text

"CTUSBDU1SF"VUIFOUJDBUFE1SPDFTTJOH'JMUFSEP"VUIFOUJDBUF private void doAuthenticate( HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { Authentication authResult; Object principal = getPreAuthenticatedPrincipal(request); Object credentials = getPreAuthenticatedCredentials(request); // …… try { PreAuthenticatedAuthenticationToken authRequest = new PreAuthenticatedAuthenticationToken( principal, credentials); authRequest.setDetails( authenticationDetailsSource.buildDetails(request)); authResult = authenticationManager.authenticate(authRequest); successfulAuthentication(request, response, authResult); } catch (AuthenticationException failed) { // …… } } $VTUPN1SF"VUIFOUJDBUFE1SPDFTTJOH'JMUFSͰ ΦʔόʔϥΠυ

Slide 78

Slide 78 text

"CTUSBDU1SF"VUIFOUJDBUFE1SPDFTTJOH'JMUFSEP"VUIFOUJDBUF private void doAuthenticate( HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { Authentication authResult; Object principal = getPreAuthenticatedPrincipal(request); Object credentials = getPreAuthenticatedCredentials(request); // …… try { PreAuthenticatedAuthenticationToken authRequest = new PreAuthenticatedAuthenticationToken( principal, credentials); // …… authResult = authenticationManager.authenticate(authRequest); successfulAuthentication(request, response, authResult); } catch (AuthenticationException failed) { // …… } }

Slide 79

Slide 79 text

͋ͤ͘͢ͱʔ͘ΜʹΜ͠ΐ͏

Slide 80

Slide 80 text

͋ͤ͘͢ͱʔ͘ΜʹΜ͠ΐ͏

Slide 81

Slide 81 text

6TFS"DDFTT5PLFO"VUIFOUJDBUJPO1SPWJEFSBVUIFOUJDBUF public Authentication authenticate(Authentication auth) throws AuthenticationException { String accessToken = Optional.ofNullable(auth.getCredentials()) .map(Object::toString) .orElse(null); if (accessToken == null) { throw new BadCredentialsException("access token not found."); } DecodedJWT decodedAccessToken = JWTUtils.decode(accessToken); // …… ΞΫηετʔΫϯͷݕূ String username = decodedAccessToken.getClaim("username").asString(); UserDetails ud = userDetailsService.loadUserDetails( new PreAuthenticatedAuthenticationToken( username, auth.getCredentials()); return new PreAuthenticatedAuthenticationToken( ud, authentication.getCredentials(), ud.getAuthorities()); }

Slide 82

Slide 82 text

6TFS"DDFTT5PLFO"VUIFOUJDBUJPO1SPWJEFSBVUIFOUJDBUF public Authentication authenticate(Authentication auth) throws AuthenticationException { String accessToken = Optional.ofNullable(auth.getCredentials()) .map(Object::toString) .orElse(null); if (accessToken == null) { throw new BadCredentialsException("access token not found."); } DecodedJWT decodedAccessToken = JWTUtils.decode(accessToken); // …… ΞΫηετʔΫϯͷݕূ String username = decodedAccessToken.getClaim("username").asString(); UserDetails ud = userDetailsService.loadUserDetails( new PreAuthenticatedAuthenticationToken( username, auth.getCredentials()); return new PreAuthenticatedAuthenticationToken( ud, authentication.getCredentials(), ud.getAuthorities()); } ΞΫηετʔΫϯͷݕূ +85ͷߏ଄Λ֬ೝ͢Δɻ +85ॺ໊Λݕূ͢Δɻ ΫϨʔϜΛݕূ͢Δɻ

Slide 83

Slide 83 text

6TFS"DDFTT5PLFO"VUIFOUJDBUJPO1SPWJEFSBVUIFOUJDBUF public Authentication authenticate(Authentication auth) throws AuthenticationException { String accessToken = Optional.ofNullable(auth.getCredentials()) .map(Object::toString) .orElse(null); if (accessToken == null) { throw new BadCredentialsException("access token not found."); } DecodedJWT decodedAccessToken = JWTUtils.decode(accessToken); // …… JWTͷݕূ String username = decodedAccessToken.getClaim("username").asString(); UserDetails ud = userDetailsService.loadUserDetails( new PreAuthenticatedAuthenticationToken( username, auth.getCredentials()); return new PreAuthenticatedAuthenticationToken( ud, authentication.getCredentials(), ud.getAuthorities()); }

Slide 84

Slide 84 text

͋ͤ͘͢ͱʔ͘ΜʹΜ͠ΐ͏

Slide 85

Slide 85 text

$VTUPN"VUIFOUJDBUJPO6TFS%FUBJMT4FSWJDFKBWB @Service public class CustomAuthenticationUserDetailsService implements AuthenticationUserDetailsService { private final CustomUserDetailsService userDetailsService; // …… @Override public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException { String username = token.getPrincipal().toString(); String accessToken = token.getCredentials().toString(); return Optional.ofNullable( userDetailsService.loadUserByUsername(username)) .map(u -> new CustomUserDetails( ((CustomUserDetails) u).getUser(), accessToken)) .orElseThrow(() -> new UsernameNotFoundException("user not found")); } }

Slide 86

Slide 86 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ

Slide 87

Slide 87 text

঺հ͢Δςετ w '03.ೝূͷςετ w 30-&Ͱύεͷ੍ݶ͕Ͱ͖ͯΔ͔ͷςετ

Slide 88

Slide 88 text

ґଘؔ܎Λ௥Ճ org.springframework.security spring-security-test test testCompile “org.springframework.security:spring- security-test:5.1.1.RELEASE”

Slide 89

Slide 89 text

4FDVSJUZ'JMUFSΛ௥Ճ @BeforeEach void beforeEach() { mockMvc = MockMvcBuilders .webAppContextSetup(context) .apply(springSecurity()) .build(); } 4FDVSJUZ.PDL.WD$POpHVSFSTTQSJOH4FDVSJUZ

Slide 90

Slide 90 text

'03.ೝূͷςετ @Test void loginSuccess() throws Exception { MvcResult result = mockMvc .perform(formLogin() .user("ruchitate").password("password")) .andReturn(); Assertions.assertThat(result.getResponse()) .extracting( MockHttpServletResponse::getStatus, MockHttpServletResponse::getRedirectedUrl) .containsExactly(302, "/success"); } 4FDVSJUZ.PDL.WD3FRVFTU#VJEFSTGPSN-PHJO ϩά ΠϯϢʔβ Λઃఆ

Slide 91

Slide 91 text

30-&Ͱύε੍ݶͰ͖ͯΔ͔ͷςετ @Test void useWith200() throws Exception { MvcResult result = mockMvc.perform(get("/users/{id}", 1) .with(user("ruchitate").roles("STAFF"))) .andExpect(status().isOk()) .andReturn(); assertEquals( "{\"name\":\"಺ཱ ྑհ\",\"username\":\"ruchitate\", \"createdAt\":\"2018-10-01T00:00:00\",\"lastSignInAt\":null}", result.getResponse().getContentAsString()); }

Slide 92

Slide 92 text

30-&Ͱύε੍ݶͰ͖ͯΔ͔ͷςετ @Test void useWith403ForAdmin() throws Exception { mockMvc.perform(get("/users/{id}", 1) .with(user("ruchitate").roles("ADMIN"))) .andExpect(status().isForbidden()) .andReturn(); }

Slide 93

Slide 93 text

ΞδΣϯμ ࠓճͷΰʔϧ 4QSJOH4FDVSJUZͱ͸ʁ '03.ೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZ8JUI"NB[PO$PHOJUP $PHOJUPೝূ࣮૷ͯ͠Έͨ 4QSJOH4FDVSJUZͷςετ ͓·͚ʢϝιουηΩϡϦςΟʣ

Slide 94

Slide 94 text

ͭͷΞ ϊςʔγϣϯ w !1SF"VUIPSJ[F w !1PTU"VUIPSJ[F w !1SF'JMUFS w !1PTU'JMUFS

Slide 95

Slide 95 text

!1SF"VUIPSJ[F @PreAuthorize("hasRole('ADMIN')") public List list() { return userRepository.findAll(); } @PreAuthorize("#role == 'ADMIN'") public List list(String role) { return userRepository.findAll(); } @PreAuthorize("#r.name == 'ruchitate'") public List list(@P("r") UserRequest request) { return userRepository.findAll(); } ϝιουʹೖΔલʹνΣοΫॲཧΛߦ͏ɻ GBMTFͷͱ͖ɺ"DDFTT%FOJFE&YDFQUJPOΛεϩʔ

Slide 96

Slide 96 text

!1PTU"VUIPSJ[F @PostAuthorize("returnObject != null && returnObject.username == 'ruchitate'") public User get(Integer id) { return userRepository.findById(id).orElse(null); } ϝιου௨աޙʹ໭Γ஋ʹରͯ͠νΣοΫॲཧΛߦ͏ɻ GBMTFͷͱ͖ɺ"DDFTT%FOJFE&YDFQUJPOΛεϩʔ

Slide 97

Slide 97 text

!1SF'JMUFS @PreFilter("filterObject.name.equals('ruchitate')") public List list(List requests) { List usernameList = requests.stream() .map(UserRequest::getName) .collect(Collectors.toList()); return userRepository .findAllByUsernameIn(usernameList); } ϝιουʹೖΔલʹҾ਺ͷதͰ৚݅ʹҰக͢ΔΦϒδΣ ΫτͷΈநग़ɻ

Slide 98

Slide 98 text

!1PTU'JMUFS @PostFilter("filterObject.username == 'ruchitate'") public List list() { return userRepository.findAll(); } ৚݅ʹҰக͢ΔΦϒδΣΫτͷΈ໭Γ஋͔Βநग़ɻ

Slide 99

Slide 99 text

·ͱΊ w ೝূɾೝՄͷྲྀΕΛཧղ͢Δʹ͸ެࣜϦϑΝ Ϩϯε w ͍࣮͟૷͠Α͏ͱͳΔͱࣅͨΑ͏ͳ'JMUFS΍ "VUIFOUJDBUJPO1SPWJEFSͷ࣮૷ΛݟΔ͔͠ w 4QSJOH4FDVSJUZ͓΋͠Ζ͍

Slide 100

Slide 100 text

͓ΘΓ

Slide 101

Slide 101 text

ࢀߟ w IUUQTEFWDMBTTNFUIPEKQTFDVSJUZ BVUIFOUJDBUJPOBOEBVUIPSJ[BUJPO w IUUQXXXBUNBSLJUDPKQBJUBSUJDMFT OFXTIUNM

Slide 102

Slide 102 text

ιʔείʔυ w IUUQTHJUIVCDPNCBJETQSJOHTFDVSJUZ XJUIDPHOJUP