๐Ÿ’ป ์ฝ”๋”ฉ ์ผ๊ธฐ : [Spring Security] '๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ' ํŽธ

ybkยท2024๋…„ 5์›” 5์ผ

spring

๋ชฉ๋ก ๋ณด๊ธฐ
27/55
post-thumbnail

๐Ÿ”” '๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ'์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž!


๐Ÿ’Ÿ Spring Security ์‚ฌ์šฉํ•ด์„œ ๋กœ๊ทธ์ธ ๋งŒ๋“ค๊ธฐ

AppConfiguration(๋กœ๊ทธ์ธ์— ํ•„์š”ํ•œ ์„ค์ •)

@Configuration
@EnableMethodSecurity
public class AppConfiguration {

    //๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ๋‚ด๊ฐ€ ์ž‘์„ฑํ•˜๋„๋ก ์Šคํ”„๋ง ๊ธฐ๋ณธ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๊ฐ€ ์•„๋‹Œ
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.disable());
        http.formLogin(login -> login.loginPage("/member/login"));
        return http.build();
    }

    // ์•”ํ˜ธํ™”
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
  • ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ์„ ํ•˜๊ธฐ ์œ„ํ•œ URL์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  • .formLogin ๋ฉ”์„œ๋“œ๋Š” ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์˜ ๋กœ๊ทธ์ธ ๋‹ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์œผ๋กœ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์˜ URL์€ /member/login์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  • BCryptPasswordEncoder : ์•”ํ˜ธํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์ธ์ฝ”๋”ฉํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.


CustomUserDetailsService(์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋กœ๋“œ)

@Component
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {

    private final MemberMapper mapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return new CustomUser(mapper.selectByEmail(username));
    }
}
  • form์—์„œ ๋ฐ›๋Š” email, password๋ž‘ ์‹œํ๋ฆฌํ‹ฐ(userDetails)์—์„œ ๋ฐ›๋Š” username, password๋ž‘ ๊ฐ™์•„์•ผ ๋กœ๊ทธ์ธ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • UserDetailsService์˜ ์ถ”์ƒ ๋ฉ”์„œ๋“œ์ธ loadUserByUsername๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•ฉ๋‹ˆ๋‹ค.
  • loadUserByUsername์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ์ด๋ฉ”์ผ์„ ๋ฐ›์•„์„œ ํ•ด๋‹น ์ด๋ฉ”์ผ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” MemberMapper๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฉ”์ผ์— ํ•ด๋‹นํ•˜๋Š” ํšŒ์› ์ •๋ณด๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž๊ฐ€ form์— ์ ์€ ์ •๋ณด์™€ loadUserByUsername ๋ฉ”์„œ๋“œ์—์„œ ๋ฐ˜ํ™˜๋œ ์ •๋ณด์™€ ๋น„๊ตํ•˜์—ฌ ์ธ์ฆํ•ฉ๋‹ˆ๋‹ค.
  • ์กฐํšŒ๋œ ํšŒ์› ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  CustomUser ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. CustomUser๋Š” UserDetails ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ์ฒด์ด๋ฉฐ ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • Spring Security๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ CustomUserDetailsService์—์„œ ๊ฐ€์ ธ์˜จ ํšŒ์› ์ •๋ณด์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋น„๊ตํ•˜์—ฌ ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

CustomUser(์‚ฌ์šฉ์ž ์‹๋ณ„ ๋ฐ ์ธ์ฆ)

@Getter
public class CustomUser extends User {
    public CustomUser(Member member) {
        super(member.getEmail(), member.getPassword(), List.of());
    }
}
  • userDetails๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๊ธฐ ๋•Œ๋ฌธ์— ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ถˆ๊ฐ€๋Šฅํ•˜์—ฌ CustomerUser ํด๋ž˜์Šค๋ฅผ ๋”ฐ๋กœ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • CustomerUser ํด๋ž˜์Šค์—์„œ Userํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์•„ User๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. super("username","password","๊ถŒํ•œ")์—์„œ username์—๋Š” Member์˜ ์ด๋ฉ”์ผ, password์—๋Š” Member์˜ password๋ฅผ ๋ฐ›์•„์™€์„œ ์„ธํŒ…ํ•ฉ๋‹ˆ๋‹ค.CustomUserDetailsService์˜ loadUserByUsername`๋ฉ”์„œ๋“œ์—์„œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋ฐ›์•„ ์ธ์ฆํ•ฉ๋‹ˆ๋‹ค.
  • User ํด๋ž˜์Šค : ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ •๋ณด๋ฅผ ๋‚˜ํƒ€๋‚ด๋ฉฐ ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

MemberService

public void signup(Member member) {
    member.setPassword(encoder.encode(member.getPassword()));
    mapper.insert(member);
}
  • insert ํ•˜๊ธฐ ์ „์— ํšŒ์›์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ฐ›์•„์™€ ์•”ํ˜ธํ™”๋ฅผ ํ•ด์ฃผ๊ณ  ์•”ํ˜ธํ™”๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ฐ›์•„์˜ต๋‹ˆ๋‹ค.
  • ํšŒ์›๊ฐ€์ž…์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•”ํ˜ธํ™”๋œ ์ƒํƒœ๋กœ ๋ฐ›์•„์•ผ ๋กœ๊ทธ์ธ์„ ํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ BCryptPasswordEncoder๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•”ํ˜ธํ™”ํ•˜๊ณ  ์•”ํ˜ธํ™”ํ•œ ๊ฒƒ์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ์ด๋ ‡๊ฒŒ ํ•ด์‹ฑ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋ณตํ˜ธํ™”๋  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, ์‚ฌ์šฉ์ž์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

navbar.jsp

  • navbar์—์„œ ๋กœ๊ทธ์ธํ•˜๋ฉด ๋ชฉ๋ก, ๊ธ€์“ฐ๊ธฐ, ํšŒ์›๋ชฉ๋ก, ๋กœ๊ทธ์•„์›ƒ ํ™”๋ฉด์ด ๋ณด์—ฌ์•ผ ํ•˜๊ณ  ๋กœ๊ทธ์•„์›ƒ์„ ํ•  ๊ฒฝ์šฐ, ๋ชฉ๋ก, ํšŒ์›๊ฐ€์ž…, ๋กœ๊ทธ์ธ ํ™”๋ฉด์ด ๋ณด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
  
<li class="nav-item">
    <a href="/" class="nav-link">
        ๋ชฉ๋ก
    </a>
</li>
<sec:authorize access="isAuthenticated()">
    <li class="nav-item">
        <a href="/add" class="nav-link">
            ๊ธ€์“ฐ๊ธฐ
        </a>
    </li>
    <li class="nav-item">
        <a href="/member/list" class="nav-link">
            ํšŒ์›๋ชฉ๋ก
        </a>
    </li>
</sec:authorize>
<sec:authorize access="not isAuthenticated()">
    <li class="nav-item">
        <a href="/member/signup" class="nav-link">
            ํšŒ์›๊ฐ€์ž…
        </a>
    </li>
    <li class="nav-item">
        <a href="/member/login" class="nav-link">
            ๋กœ๊ทธ์ธ
        </a>
    </li>
</sec:authorize>
<sec:authorize access="isAuthenticated()">
    <li class="nav-item">
        <a href="/logout" class="nav-link">
            ๋กœ๊ทธ์•„์›ƒ
        </a>
    </li>
</sec:authorize>
  • <sec:authorize access="isAuthenticated()"> : ๋กœ๊ทธ์ธ ํ•˜๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์—ˆ์„ ๋•Œ ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
  • <sec:authorize access="not isAuthenticated()"> : ๋กœ๊ทธ์ธ์ด ๋˜์ง€ ์•Š์•„ ์ ‘๊ทผ์ด ์ œํ•œ๋˜์–ด ์ผ๋ถ€ ๊ธฐ๋Šฅ๋งŒ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
profile
๊ฐœ๋ฐœ์ž ์ค€๋น„์ƒ~

0๊ฐœ์˜ ๋Œ“๊ธ€