12-01 02:24
Recent Posts
Recent Comments
๊ด€๋ฆฌ ๋ฉ”๋‰ด

miinsun

[Spring] Spring Security ๋กœ๊ทธ์ธ/๋กœ๊ทธ์•„์›ƒ/ํŒจ์Šค์›Œ๋“œ ์•”ํ˜ธํ™” ๊ธฐ๋Šฅ ๊ตฌํ˜„ ๋ณธ๋ฌธ

WebApp/Spring

[Spring] Spring Security ๋กœ๊ทธ์ธ/๋กœ๊ทธ์•„์›ƒ/ํŒจ์Šค์›Œ๋“œ ์•”ํ˜ธํ™” ๊ธฐ๋Šฅ ๊ตฌํ˜„

miinsun 2021. 12. 20. 19:10

๐Ÿ’ป ์‹ค์Šต ํ™˜๊ฒฝ

Language: Java8
Spring Boot
IDE: IntelliJ

 

๐Ÿ’ฌ ์š”๊ตฌ ์‚ฌํ•ญ

Spring Security๋ฅผ ์ด์šฉํ•ด ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ, ํŒจ์Šค์›Œ๋“œ ์•”ํ˜ธํ™” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค

 

๐Ÿ“Œ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ํ”„๋ ˆ์ž„์›Œํฌ ์ถ”๊ฐ€

build.gradleํŒŒ์ผ์— ์•„๋ž˜ ํ•˜๋‹จ์— ์ฝ”๋“œ ์ถ”๊ฐ€

  // ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ
  implementation 'org.springframework.boot:spring-boot-starter-security'
  // Thymeleaf (๋ทฐ ํ…œํ”Œ๋ฆฟ ์—”์ง„)
  implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

 

๐Ÿ“Œ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ํ™œ์„ฑํ™”

WebSecurityConfig.java ํŒŒ์ผ ์ƒ์„ฑ

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity // ์Šคํ”„๋ง Security ์ง€์›์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•จ
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.headers().frameOptions().disable();

        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .defaultSuccessUrl("/")
                .permitAll()
                .and()
                .logout()
                .permitAll();
    }
}

 

๐Ÿ“Œ Spring Security ๊ธฐ๋ณธ ๋™์ž‘ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

  • Username : user
  • Password : Springํ”„๋กœ์ ํŠธ์˜ ๋กœ๊ทธ 'Using generated security password : ~~'๋ฅผ ํ™•์ธ
    • ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ ์‹œ ๋ณ€๊ฒฝ

 

๐Ÿ“Œ Spring Security๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™”

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์—์„œ ์ œ๊ณตํ•ด์ฃผ๊ณ  ๊ถŒ๊ณ ๋˜๋Š” 'BCrypt' ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ํŒจ์Šค์›Œ๋“œ๋ฅผ ์•”ํ˜ธํ™”ํ•˜์—ฌ DB์— ์ €์žฅ

1. WebSecurityConfig ํŒŒ์ผ์— ํ•ด๋‹น ํ•จ์ˆ˜ ์ถ”๊ฐ€

  @Bean
  public BCryptPasswordEncoder encodePassword() {
  return new BCryptPasswordEncoder();
  }

 

2. User Register ํšŒ์›๊ฐ€์ž… ํ•จ์ˆ˜ Password ๋“ฑ๋ก ๋ถ€๋ถ„ ์ˆ˜์ •

import org.springframework.security.crypto.password.PasswordEncoder;

private final PasswordEncoder passwordEncoder;

// ํŒจ์Šค์›Œ๋“œ ์ธ์ฝ”๋”ฉ
String password = passwordEncoder.encode(requestDto.getPassword());

์™ผ์ชฝ๋ถ€ํ„ฐ ์•”ํ˜ธํ™” ์ „/ํ›„

 

๐Ÿ“Œ Spring Security๋กœ ๋กœ๊ทธ์ธ ๊ตฌํ˜„

AuthenticationManager๋ฅผ ํ†ตํ•ด ์ธ์ฆ/์ธ๊ฐ€ ์„ฑ๊ณต ์‹œ์—๋งŒ, Controller์—๊ฒŒ ํšŒ์› ์ •๋ณด(UserDetails)๋ฅผ ์ „๋‹ฌํ•˜๋„๋ก ํ•œ๋‹ค.

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๋ฅผ ํ†ตํ•œ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ ๊ณผ์ •

์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๊ฐ€ ๊ตฌํ˜„ํ•ด์•ผ ํ•  ํด๋ž˜์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

    1. UserDetailsService ์ธํ„ฐํŽ˜์ด์Šค → UserDetailsServiceImpl ํด๋ž˜์Šค
    2. UserDetails ์ธํ„ฐํŽ˜์ด์Šค → UserDetailsImpl ํด๋ž˜์Šค

 

1) UserDetailsServiceImpl ์ƒ์„ฑ

import com.sparta.springcore.model.User;
import com.sparta.springcore.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class UserDetailsServiceImpl implements UserDetailsService{

	@Autowired
	private UserRepository userRepository;

	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("Can't find " + username));

        return new UserDetailsImpl(user);
    }
}

 

2) UserDetailsImpl.java ์ƒ์„ฑ

import com.sparta.springcore.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.Collections;

public class UserDetailsImpl implements UserDetails {

    private final User user;

    public UserDetailsImpl(User user) {
        this.user = user;
    }

    public User getUser() {
        return user;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Collections.emptyList();
    }
}
 

๐Ÿ“Œ Spring Security๋กœ ๋กœ๊ทธ์•„์›ƒ ๊ตฌํ˜„

GET '/user/logout'์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ ๋งŒ์œผ๋กœ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๊ฐ€ ๋กœ๊ทธ์•„์›ƒ์„ ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค.

@Configuration
@EnableWebSecurity // ์Šคํ”„๋ง Security ์ง€์›์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•จ
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.headers().frameOptions().disable();

        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .defaultSuccessUrl("/")
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/user/logout")
                .permitAll();
    }
}

 

Comments