스프링 시큐리티는 안전한 로그인을 위해 가장 많이 사용되며, 계정별로 권한을 부여할 때 사용한다. 간단한 방식으로 시큐리티가 적용된 로그인 페이지를 만들어보도록 한다.
* 스프링 시큐리티 간단한 계정 설정
application.yml에서 임의의 계정을 추가할 수 있다. 하지만, 1개밖에 추가하지못한다.
(다수 계정 설정을 위해서 WebSecurityConfigurerAdapter를 상속받은 클래스가 필요하다.)
spring:
security:
user:
name: user1
password: 1111
roles: USER
스프링 시큐리티에서 계정 정보는 크게 name, password, roles 3가지가 필요하다.
* 스프링 시큐리티 로그인 정보 확인하기
@RequestMapping("/auth")
public Authentication auth() {
return SecurityContextHolder.getContext().getAuthentication();
}
SecurityContextHolder.getContext().getAuthentication(); 에 현재 로그인한 인증정보가 담겨 있어 로그인 정보를 확인할 수 있다.
{
"authorities": [
{
"authority": "ROLE_USER"
}
],
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": "CF8A2CF51F7CA17C21F553BD9A338D9B"
},
"authenticated": true,
"principal": {
"password": null,
"username": "user1",
"authorities": [
{
"authority": "ROLE_USER"
}
],
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"enabled": true
},
"credentials": null,
"name": "user1"
}
authorities, details, authenticated, principal, credentials, name 등의 정보를 담고 있다.
* @PreAuthroize로 계정별 권한 제한하기
@PreAuthorize("hasAnyAuthority('ROLE_USER')")
@RequestMapping("/user")
public SecurityMessage user() {
return SecurityMessage.builder()
.auth(SecurityContextHolder.getContext().getAuthentication())
.message("User 정보")
.build();
}
@PreAuthorize("hasAnyAuthority('ROLE_USER')") 는 로그인 하는 사용자가 USER 계정권한을 가지고 있어야 한다는 조건을 알려준다.
{
"auth": {
"authorities": [
{
"authority": "ROLE_USER"
}
],
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": "0FE9C835450BB3211729206D7585A15C"
},
"authenticated": true,
"principal": {
"password": null,
"username": "user1",
"authorities": [
{
"authority": "ROLE_USER"
}
],
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"enabled": true
},
"credentials": null,
"name": "user1"
},
"message": "User 정보"
}
@PreAuthorize("hasAnyAuthority('ROLE_ADMIN')")
@RequestMapping("/admin")
public SecurityMessage admin() {
return SecurityMessage.builder()
.auth(SecurityContextHolder.getContext().getAuthentication())
.message("관리자 정보")
.build();
}
@PreAuthorize("hasAnyAuthority('ROLE_ADMIN')") 는 로그인 하는 사용자가 ADMIN 계정권한을 가지고 있어야 한다는 조건을 알려준다.
"auth": {
"authorities": [
{
"authority": "ROLE_USER"
}
],
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": "0FE9C835450BB3211729206D7585A15C"
},
"authenticated": true,
"principal": {
"password": null,
"username": "user1",
"authorities": [
{
"authority": "ROLE_USER"
}
],
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"enabled": true
},
"credentials": null,
"name": "user1"
},
"message": "관리자 정보"
}
하지만, 현재 계정 관리 시큐리티 설정이 부족해서 USER 권한으로 ADMIN 정보를 확인할 수 있다. 계정 권한에 따른 스프링 시큐리티 설정이 필요하다.
* WebSecurityConfigurerAdapter 상속받기
@PreAuthoriz()로 권한에 따른 계정관리가 정상 작동하기 위해서 @EnableGlobalMethodSecurity(prePostEnabled = true) 설정을 추가해야 한다. 해당 클래스에서는 configure 메서드를 많이 사용한다. 매개변수가 다른 재정의 configure 메서드가 3개나 있기 때문에 각 차이점에 유의해서 사용한다.
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
해당 클래스에서, 여러개의 계정을 만들 수 있다.
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(User.builder()
.username("user2")
.password(passwordEncoder().encode("2222"))
.roles("USER")
)
.withUser(User.builder()
.username("user3")
.password(passwordEncoder().encode("3333"))
.roles("ADMIN")
);
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
AuthenticationManagerBuilder로를 매개변수로 가지는 configure 메서드는 계정 생성을 담당한다. inMemoryAuthentication()으로 내부 DB에서 사용 가능한 계정을 만든다. user2는 권한이 USER이고 user3는 권한이 ADMIN 이다. USER,ADMIN 권한을 가진 계정은 각각 /user, /admin 경로로만 접속이 가능하다. 서로의 URI로 접속하려고 하면 403 권한이 없다는 오류가 리턴된다.
비밀번호를 그냥 raw 데이터로 만들면 보안적으로 오류가 나기 떄문에 PasswordEncoder를 새롭게 등록해주어야 한다.
* 홈페이지에 누구나 접근 가능하게 풀어주고 싶다면?
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) ->
requests.antMatchers("/")
.permitAll()
.anyRequest()
.authenticated()
);
}
"/" 경로에는 어떠한 요청이든 모두 허가하므로 리소스가 누구에게나 접근이 된다.
'Spring > Spring Security' 카테고리의 다른 글
UserDetailsService (0) | 2021.10.11 |
---|---|
BaiscToken으로 웹/모바일 로그인 인증 구현하기 (0) | 2021.10.11 |
BasicAuthentication 인증 (0) | 2021.10.11 |
authentication 메커니즘 (0) | 2021.10.08 |
basic login 과정 (0) | 2021.10.08 |