728x90
반응형
시큐리티 설정 커스터마이징
기본 프로젝트 구조와 의존성은 스프링 시큐리티 1부 참고
페이지 별 로그인 설정 예제
1. HelloController
및 index.html
, hello.html
, my.html
추가
// HelloController.java
@Controller
public class HelloController {
@GetMapping(value="/hello")
public String hello() {
return "hello";
}
@GetMapping(value="/my")
public String my() {
return "my";
}
}
// index.html
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>Page Title</title>
</head>
<body>
<h1>Hello Spring Boot Security</h1>
<a href="/hello">Hello</a>
<a href="/my">My</a>
</body>
</html>
// hello.html
...
<body>
<h1>Hello</h1>
</body>
</html>
// my.html
...
<body>
<h1>My</h1>
</body>
</html>
2. SecurityConfig 추가
// SecurityConfig.java
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 스프링 부트가 제공하는 SecurityAutoConfigutaion은 미사용
// WebSecurityConfigurerAdapter 타입의 Bean을 등록했기 때문에
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/hello").permitAll() // antMatcher로 root, hello 요청은 접근 가능 처리
.anyRequest().authenticated() // 그 외 요청은 인증정보 필요
.and()
.formLogin() // 인증이 안되어있으니까 걸림, accept header 에 html이 존재해서
.and()
.httpBasic() // html이 없는 경우
;
}
}
결과 확인
1. index.html
접근 시
2. hello.html
접근 시
3. my.html
접근 시
SecurityConfig
에서 root(/)
, /hello
만 접근 허가를 하였기 때문에 /my
접근 시 스프링 시큐리티에서 제공하는 로그인 페이지 표시
User 정보 커스터마이징
공통
Account
, AccountService
, AccountRepository
및 JPA
, H2
의존성 추가
// pom.xml
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- H2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
// Account.java
@Entity
public class Account {
@Id @GeneratedValue
private Long id;
private String username;
private String password;
getter/setter
}
// AccountService.java
@Service
public class AccountService {}
// AccountRepository.java
public interface AccountRepository extends JpaRepository<Account, Long> {}
UserDetailsServce 구현
1. AccountService
수정
// AccountService.java
@Service
public class AccountService implements UserDetailsService {
// 보통 Service 계층에 UserDetailsService 구현
// 별개로 다른 클래스를 만들어서 UserDetailsService 인터페이스를 구현해도 상관 없다.
// UserDetailsService 타입의 Bean이 등록이 되어있어야 스프링 부트가 만들어주는 User가 더 이상 생성되지 않는다.
// 커스텀 User 사용 가능하다.
@Autowired
private AccountRepository accountRepository;
public Account createAccount(String username, String password) {
Account account = new Account();
account.setUsername(username);
account.setPassword(password);
return accountRepository.save(account);
}
// 로그인 처리 시 호출
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<Account> byUsername = accountRepository.findByUsername(username);
Account account = byUsername.orElseThrow(() -> new UsernameNotFoundException(username));
return new User(account.getUsername(), account.getPassword(), authorites());
}
// Authority
private Collection<? extends GrantedAuthority> authorites() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
}
2. AccountRepository
수정
// AccountRepository.java
public interface AccountRepository extends JpaRepository<Account, Long> {
Optional<Account> findByUsername(String username);
}
3. User
객체 생성을 위해 AccountRunner
생성
// AccountRunner.java
@Component
public class AccountRunner implements ApplicationRunner {
@Autowired
AccountService accountService;
@Override
public void run(ApplicationArguments args) throws Exception {
Account jinseo = accountService.createAccount("jinseo", "1234");
System.out.println(jinseo.getUsername() + " / " + jinseo.getPassword());
}
}
결과 확인
PasswordEncoder 설정 및 사용
1. SecurityConfig
수정
// SecurityConfig.java
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/hello").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic()
;
}
// PasswordEncoder 를 사용하지 않는 방법
// 절대 사용 X
// @Bean
// public PasswordEncoder passwordEncoder() {
// return NoOpPasswordEncoder.getInstance();
// }
// 권장하는 PasswordEncoder 사용 방법
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
2. AccountService
수정
// AccountService.java
@Service
public class AccountService implements UserDetailsService {
@Autowired
private AccountRepository accountRepository;
@Autowired
private PasswordEncoder passwordEncoder;
public Account createAccount(String username, String password) {
Account account = new Account();
account.setUsername(username);
account.setPassword(passwordEncoder.encode(password)); // Password Encoding
return accountRepository.save(account);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<Account> byUsername = accountRepository.findByUsername(username);
Account account = byUsername.orElseThrow(() -> new UsernameNotFoundException(username));
return new User(account.getUsername(), account.getPassword(), authorites());
}
private Collection<? extends GrantedAuthority> authorites() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
}
결과 확인
참고
https://docs.spring.io/spring-security/site/docs/current/reference/html5/
728x90
반응형
'Dev > Spring Boot' 카테고리의 다른 글
[스프링 부트 개념과 활용] 스프링 REST 클라이언트 2부 (0) | 2020.09.03 |
---|---|
[스프링 부트 개념과 활용] 스프링 REST 클라이언트 1부 (0) | 2020.09.03 |
[스프링 부트 개념과 활용] 스프링 시큐리티 1부 (0) | 2020.08.31 |
[스프링 부트 개념과 활용] 스프링 데이터 12부 (0) | 2020.08.31 |
[스프링 부트 개념과 활용] 스프링 데이터 11부 (0) | 2020.08.28 |
댓글