과거에 프레임워크 없이 프로그래밍을 할 때는 , 웹이 모든 url 접근에 대해서 세션을 체크하여 로그인했는지 그리고 권한이 있는지를 체크하는 로직을 넣을 때, 이런 체크 로직들이 원래 만들고자 했던 비지니스 로직의 이해를 방해하기 때문에 모든 웹 애플리케이션의 기능을만들고 맨 나중에 한꺼번에 넣곤했다.
서로 다른 사람들이 각자 자기만의 방법으로 인증과 접근권한의 설정 로직을 만들면 서로 간에도 파악해야 할 부분이 많이 생기고, 그래서 오랜기간 같이 작업을 하던 팀원이 아니면 서로의 조직을 빠르게 파악하지 못하는 등 단점이 생기기도 하였다.
스프링 시큐리티는 스프링 기반의 애플리케이션의 보안, 즉 사용자 인증과 접근권한의 설정을 담당하는 프레임워크이다.
스프링 시큐리티는 보안과 관련해서 체계적으로 많은 옵션들을 지원해주기 때문에 이런 단순 반복적인 작업이지만 매우 중요한 작업인 보안 작업을 쉽고 간단하게 적용할 수 있게 한다.
그리고 스프링 시큐리티를 이용하면 누가 만들어도 같은 방식으로 만들어지기 때문에 개발자 간의 의사소통이나 후임 또는 신입사원에게 인수인계를 했을 때 쉽게 이해시킬 수 있다.
이것이 프레임워크를 이용해서 개발하는 이유이자, 장점이자.
@Configuration
이 클래스를 빈으로 등록하는데 스프링 설정으로 사용한다는 의미
@EnableWebSecurity
스프링 시큐리티의 기능을 활성화하겠다는 의미
package com.study.springboot.auth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/css/**", "/js/**", "/img/**").permitAll()
.antMatchers("/guest/**").permitAll()
.antMatchers("/member/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated();
http.formLogin()
.permitAll();
http.logout()
.permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password(passwordEncoder().encode("1234")).roles("USER")
.and()
.withUser("admin").password(passwordEncoder().encode("1234")).roles("ADMIN");
// ROLE_ADMIN 에서 ROLE_는 자동으로 붙는다.
}
// passwordEncoder() 추가
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
스프링 시큐리티를 사용할 클래스에 WebSecurityConfigurerAdapter을 extends한다.
스프링 시큐리티를 적용하기 위해 configure 메서드를 오버라이딩해서 시큐리티 구성 내용을 구성한다.
http.authorizeRequests() 이하 부터는 url 요청에 대한 허용여부를 설정한다. 설정 내용은 겹치는 부분이 있다면 뒤의 설정이 앞의 설정 내용을 계속해서 덮어쓴다.
그래서 앞부분에 가장 넓은 범위로 허용범위를 정하고 뒤에서 범위를 좁혀 부분적으로 다시 지정하는 방식을 취한다.
andMatchar("/").permitAll() : 루트(/)url 요청에 대해서 모두에게 허용하는 세팅
/css 아래 모든 url요청, /js 아래 모든 url 요청 및 /img 아래 모든 url 요청에 대해서는 모두에게 허용하는 세팅
/guest 아래 모든 url 요청에 대해서 모두에게 허용하는 세팅
/member 아래 url 요청은 "USER"나 "ADMIN" 역할(role)을 가지고 있어야 한다고 세팅
/admin 아래 url 요청은 "ADMIN" 역할을 가지고 있어야 한다고 세팅
http.formLogin() : 로그인 폼 url은 모두에게 허용하는 세팅
http.logou() : 로그아웃 url 요청은 모두에게 허용하는 세팅
아래의 configureGlobal 메서드에서는 등록이 간단한 인메모리(inMemory)방식의 인증 사용자를 등록한다.
auth.inMemotyAuthentication() : 인메모리 방식의 인증 사용자를 등록
withUser("user").password(passwordEncoder().encode("1234").role("USER") : 사용자 이름 user, 비밀번호 1234, 역할 : USER 로 사용자를 등록한다.
withUser("admin").password(passwordEncoder().encode("1234").role("ADMIN") : 사용자 이름 admin, 비밀번호 1234, 역할 : USER 로 사용자를 등록한다.
BCryptPasswordEncoder는 비밀번호의 인코딩 방식을 정한다.
스프링 시큐리티 암호화 클래스 종류
스프링 시큐리티는 PasswordEncoder 인터페이스를 구현한 클래스로 다음 3가지 클래스를 제공하낟.
- org.springframeword.security.crypto.bcrypt.BCryptPasswordEncoder
- 스프링 시큐리티에서 기본적으로 사용하는 암호화 방식이다.
- org.springframeword.security.crypto.password.StandardPasswordEncoder
- SHA-256 암호화를 사용한다.
- org.springframeword.security.crypto.password.NoOpPasswordEncoder
- 암호화 하지 않은 데이터를 암호화 한것처럼 사용할 때 사용한다.
NoOpPasswordEncoder 클래스는 암호화 기능을 수행하지 않는 암호화 클래스이다.
그래서 암호화하기 위해 encode 메서드에 암호화할 문자열을 넣어도 실제로는 암호화 기능을 수행하지 않고 입력받은 문자열 그대로 리턴해준다.
이 클래스는 암호화 기능을 수행하는지에 대한 테스트용으로 만들어진 클래스이므로, 실제 프로젝트에서는 사용하면 안된다.
스프링 시큐리티 측에서는 신규로 개발하는 시스템이라면 BCryptPasswordEncoder 클래스를 사용하는 bcrypt 해시 알고리즘 사용을 권장한다.
다만 기존 sha 해시 알고리즘을 적용한 상황이라면 StandardPasswordEncoder를 사용하면 된다.
'Back-end' 카테고리의 다른 글
데이터베이스 프로그래밍 (0) | 2021.09.04 |
---|---|
시큐리티 커스텀 로그인 폼 (0) | 2021.09.03 |
JSP의 액션태그 (0) | 2021.08.29 |
JSP의 세션관리 (0) | 2021.08.28 |
JSP의 에러처리 (0) | 2021.08.21 |