본문 바로가기

Spring 정리/Spring Security

간단한 로그인 페이지 만들기

반응형

스프링 시큐리티는 안전한 로그인을 위해 가장 많이 사용되며, 계정별로 권한을 부여할 때 사용한다. 간단한 방식으로 시큐리티가 적용된 로그인 페이지를 만들어보도록 한다. 

 

 

* 스프링 시큐리티 간단한 계정 설정

 

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