Home Spring Security, Password Encoder
Post
Cancel

Spring Security, Password Encoder

Password Encoder

  • 실제 사용자의 password 정보는 암호화되어 저장되기 때문에 추가적인 검증 필요.

  • AuthenticationProvider : UserDetailsServicePasswordEncoder로 구성되어 있음.

    • UserDetailsService : 사용자 세부 정보 서비스
    • PasswordEncoder : 사용자 암호를 검증
      • BCryptPasswordEncoder 사용.


PasswordEncoder

  • 의존성 추가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Slf4j
@Configuration
@RequiredArgsConstructor
public class AngrySecurityConfiguration {

  private final CustomCorsConfig customCorsConfig;
  private final CsrfTokenLoggerFilter csrfTokenLoggerFilter;
  private final CsrfTokenValidFilter csrfTokenValidFilter;

  @Value("${spring.profiles.active}")
  private String ACTIVE;

  @Bean
  public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    //    ...
  }

  private HttpSecurity httpSecurity(HttpSecurity http) throws Exception {
    //    ...
  }

  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

}

AuthenticationProvider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthenticationProviderService implements AuthenticationProvider {

  private final PasswordEncoder passwordEncoder;
  private final JpaUserDetailsService jpaUserDetailsService;

  @Override
  @Transactional
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {

    String email = authentication.getName();
    String password = authentication.getCredentials().toString();
    UserDetails userDetails = jpaUserDetailsService.loadUserByUsername(email);
    boolean passwordValidate = passwordEncoder.matches(password, userDetails.getPassword());

    if (passwordValidate) {
      return new UsernamePasswordAuthenticationToken(
        userDetails.getUsername(),
        userDetails.getPassword(),
        userDetails.getAuthorities()
      );
    } else {
      throw new BadCredentialsException("Something went wrong!");
    }

  }

  @Override
  public boolean supports(Class<?> authentication) {
    return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
  }

}


테스트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class SecurityAccessLimitTest extends SecuritySetup {

  @Nested
  @Order(1)
  @DisplayName("admin test")
  class AdminTest {
    @Test
    @Order(1)
    void admin_get_pass() throws Exception {
      accessLimitTestHelper("/admin", admin, HttpMethod.GET).andExpect(status().isOk());
    }

    @Test
    @Order(2)
    void user_get_fail() throws Exception {
      accessLimitTestHelper("/user", admin, HttpMethod.POST).andExpect(status().isForbidden());
    }

    @Test
    @Order(3)
    void guest_get_fail() throws Exception {
      accessLimitTestHelper("/guest", admin, HttpMethod.PATCH).andExpect(status().isForbidden());
    }

    @Test
    @Order(4)
    void basic_get_pass() throws Exception {
      accessLimitTestHelper("/basic", admin, HttpMethod.PUT).andExpect(status().isOk());
    }
  }

  @Nested
  @Order(2)
  @DisplayName("user test")
  class UserTest {
    @Test
    @Order(1)
    void admin_get_fail() throws Exception {
      accessLimitTestHelper("/admin", user, HttpMethod.GET).andExpect(status().isForbidden());
    }

    @Test
    @Order(2)
    void user_get_pass() throws Exception {
      accessLimitTestHelper("/user", user, HttpMethod.POST).andExpect(status().isOk());
    }

    @Test
    @Order(3)
    void guest_get_fail() throws Exception {
      accessLimitTestHelper("/guest", user, HttpMethod.PATCH).andExpect(status().isForbidden());
    }

    @Test
    @Order(4)
    void basic_get_fail() throws Exception {
      accessLimitTestHelper("/basic", user, HttpMethod.PUT).andExpect(status().isOk());
    }
  }

  @Nested
  @Order(3)
  @DisplayName("guest test")
  class GuestTest {
    @Test
    @Order(1)
    void admin_get_fail() throws Exception {
      accessLimitTestHelper("/admin", guest, HttpMethod.GET).andExpect(status().isForbidden());
    }

    @Test
    @Order(2)
    void user_get_fail() throws Exception {
      accessLimitTestHelper("/user", guest, HttpMethod.POST).andExpect(status().isForbidden());
    }

    @Test
    @Order(3)
    void guest_get_pass() throws Exception {
      accessLimitTestHelper("/guest", guest, HttpMethod.PATCH).andExpect(status().isOk());
    }

    @Test
    @Order(4)
    void basic_get_pass() throws Exception {
      accessLimitTestHelper("/basic", guest, HttpMethod.PUT).andExpect(status().isOk());
    }
  }

}

password_encoder

This post is licensed under CC BY 4.0 by the author.