ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [스프링] 시큐리티 - 2 (DB 연동)
    Spring 2020. 10. 5. 19:02

    - 참고 : 인프런 >>스프링 시큐리티 (백기선 강의)

    - 참고 : github

     

    [준비]

    1. JPA 의존성 추가

    2. H2 Database 의존성 추가

     

    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
    	<groupId>com.h2database</groupId>
    	<artifactId>h2</artifactId>
    	<scope>runtime</scope>
    </dependency>
    

     

    "UserDetailsService" ? 

     - 스프링 시큐리티에서 제공

    - 스프링 시큐리티에서 DAO(Data access object) 구현체를 통해 User의 정보를 가져와 "UserDetails" 타입으로 캐스팅

      ex)  예제

    1. 유저 정보를 DB에서 찾는다. >> "user"

    Account account = accountRepository.findByUsername(username);

     

    2. "user" >> UserDetail로 변경

    return User.builder()
    .username(account.getUsername())
    .password(account.getPassword())
    .roles(account.getRole())
    .build();

     

    [예제]

     

    1. Account (User 정보를 담는 Table, Entity) 생성

    @Entity
    @Getter
    @Setter
    public class Account {
    	@Id
    	@GeneratedValue
    	private Long id;
    
    	@Column(unique = true)
    	private String username;
    
    	private String password;
    
    	private String role;
    
    }
    

     

    2.AccountRepository 생성

    public interface AccountRepository extends JpaRepository<Account,Long> {
    	Account findByUsername(String username);
    }
    

     

    3. AccountService 생성 >> "UserDetailService" 구현체

    @Service
    @RequiredArgsConstructor
    public class AccountService implements UserDetailsService {
    
    	private final AccountRepository accountRepository;
    
    	@Override
    	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    		Account account = accountRepository.findByUsername(username);
    
    		if(account == null){
    			throw new UsernameNotFoundException(username);
    		}
    
    		return User.builder()
    			.username(account.getUsername())
    			.password(account.getPassword())
    			.roles(account.getRole())
    			.build();
    	}
    
    	public Account createNew(Account account) {
    		account.setPassword("{noop}" + account.getPassword());
    		return accountRepository.save(account);
    	}
    }

     

    4. 유저 생성 API 추가 

    @RestController
    @RequiredArgsConstructor
    public class AccountController {
    	private final AccountService accountService;
    
    	@GetMapping("/account/{role}/{username}/{password}")
    	public Account createAccount(@ModelAttribute Account account) {
    
    		return accountService.createNew(account);
    	}
    }

     

    Security config

    @Configuration
    @EnableWebSecurity
    @RequiredArgsConstructor
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    	private final AccountService accountService;
    
    	@Override
    	protected void configure(HttpSecurity http) throws Exception {
    
    		http.authorizeRequests()
    			.mvcMatchers("/","/info","/account/**").permitAll()
    			.mvcMatchers("/admin").hasRole("ADMIN")
    			.anyRequest().authenticated();
    
    		http.formLogin();
    		http.httpBasic();
    	}
    
    	@Override
    	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    		auth.userDetailsService(accountService);
    	}
    
    	@Bean
    	@Override
    	public AuthenticationManager authenticationManagerBean() throws Exception {
    		return super.authenticationManagerBean();
    	}
    
    }

     

     

    [시나리오]

     

    1.  유저생성

       - > GET: localhost:8080/account/ADMIN/admin/123

     

    2. 로그인 

     admin / 123

     

    3. "/admin" 접근 

     

    패스워드 인코더 추가

     

    -> "{noop}"를 없앤다. 

    • 비밀번호는 반드시 인코딩해서 저장
    • 다양한 해싱 전략의 패스워드를 지원

     

    1. 패스워드 인코더 추가 

    @Bean
    public PasswordEncoder passwordEncoder(){
      return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

     

    2. 인코딩

    public Account createNew(Account account) {
      account.setPassword(passwordEncoder.encode(account.getPassword()));
      return accountRepository.save(account);
    }

     

     

    'Spring' 카테고리의 다른 글

    [스프링] 시큐리티 -4 (SecurityContextHolder)  (0) 2020.10.09
    [스프링] 시큐리티 -3 (Test)  (0) 2020.10.09
    [스프링] 시큐리티 - 1 (인메모리 유저)  (0) 2020.10.05
    [스프링] @Cacheable  (0) 2020.09.15
    [스프링배치] 개념  (0) 2020.06.14

    댓글

Designed by Tistory.