티스토리 뷰

Spring Security는 직전 포스팅에서도 언급했듯, Config 클래스를 생성하여 내부 설정을 개발 목적에 맞춰 커스터마이징할 수 있다.


1. Resource 설정

 

Config 클래스가 상속받는 WebSecurityConfigurerAdapter 클래스의 내부 추상 메서드 configure를 재정의하여 사용할 수 있는데, 아래 코드와 같이 HttpSecurity 객체를 인자로 받아 사용자 인증, 인가를 제어할 수 있으며 로그인 페이지, 로그아웃 페이지, 로그인 성공 페이지 등 각 요청에 맞게 리다이렉트 요청 또한 설정할 수 있다.

 

◎SecurityConfig.java

package com.choonham.security.config;

import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@Log4j2
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity security) throws Exception{
        // 매개변수 security를 통해 전달받은 HttpSecurity 객체를 이용하여 인증, 인가를 제어
        security.authorizeRequests().antMatchers("/").permitAll();
        security.authorizeRequests().antMatchers("/sample/member/**").authenticated(); // 인증된 사용자만
        security.authorizeRequests().antMatchers("/sample/manager/**").hasRole("MANAGER"); // 인가하기 위한 규칙
        security.authorizeRequests().antMatchers("/sample/admin/**").hasRole("ADMIN");

        // 크로스 스크립트 위조 요청에 대한 설정 : csrf()

        security.csrf().disable(); //RestFull을 사용하기 위해서는 CSRF 기능을 비활성화 해야한다.
        // 로그인, 로그인 성공
        security.formLogin().loginPage("/sample/login").defaultSuccessUrl("/sample/loginSuccess", true);
        // 로그인 실패
        security.exceptionHandling().accessDeniedPage("/sample/error");

        security.logout().invalidateHttpSession(true).logoutSuccessUrl("/login");
    }

}

 1. 특정 경로에 대한 권한을 가진 사용자만 접근을 허용할 경우, AuthorizedUrl 객체의 매서드를 이용.


     AuthorizedUrl은 HttpSecurity의 authorizeRequests() 를 호출할 때 리턴되는
     ExpressionInterceptUrlRegistry의 antMatchers() 메서드를 통해 얻어낸다.
 

2. 모든 사용자에게 접근 권한을 부여할 경우 : AuthorizedUrl의 permitAll() 을 이용하여 접근허가

 

3. formLogin() : 로그인(인증) 페이지 설정


    => loginPage("URL 패턴") : 로그인이 필요한 url 로 접근하면 URL 패턴 화면으로 이동
 

4. logout() : 로그아웃 페이지 설정

 

 Spring Security의 인증 처리 방식은 기본적으로 HttpSession 을 이용.
 따라서 브라우저가 종료되면 해당 세션도 자동으로 종료
 만약 브라우저를 종료하지 않고, 세션을 종료하려면 사용자가 로그아웃 요청을 하고, 서버는 해당 세션을 강제로 종료*     => invalidateHttpSession(true) : 현재 브라우저와 연관된 세션을 강제 종료
   => logoutSuccessUrl("URL 패턴") : 로그아웃 후 이동활 화면으로 리다이렉트


이제 간단하게 login.html 과 loginSuccess.html을 생성하고, 컨트롤러가 해당 요청을 처리하게 설정해주면 된다.

(login.html, loginSuccess.html 코드는 생략)

 

◎Controller.java

package com.choonham.security.controller;

import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@Log4j2
@RequestMapping("/sample/")
public class SampleController {

    @GetMapping("/all") // 로그인을 하지 않은 사용자도 접근할 수 있는 all
    public void exAll() {
        log.info("exAll...");
    }

    @GetMapping("/member") // 로그인한 사용자만 접근할 수 있는 member
    public void exMember() {
        log.info("exMember...");
    }

    @GetMapping("/admin") // 관리자만 접근할 수 있는 admin
    public void exAdmin() {
        log.info("exAdmin...");
    }

    @GetMapping("/login")
    public void login() {
    }

    @GetMapping("/loginSuccess")
    public void loginSuccess() {
    }

    @GetMapping("/error")
    public void loginError() {
    }
}

확인해보면, 다음과 같이 커스텀한 login페이지와 로그인을 했을 때, 성공 페이지가 출력되는 걸 확인할 수 있다.


2. PasswordEncoder

 passwordEncoder는 말 그대로 패스워드를 인코딩하는 것인데, 주목적은 패스워드를 암호화하는 것이다. 이는 인증, 인가 절차를 코딩할 때 없어서는 안되는 필수 설정이기 때문에 반드시 해주어야 한다.

 

Spring Security Reference 문서에 보면, 다음과 같이 여러 종류의 PasswordEncoders 가 있는데, 가장 대표적으로 쓰이는 것이 바로 BCrypt2 방식이다.

BCrypt2 방식은 bcrypt라는 해시 함수를 이용해서 패스워드를 암호화하는 것인데, 이 방식으로 암호화된 패스워드는 원래대로 복호화가 아예 불가능하고, 매번 암호화된 값도 다르게 된다. (길이는 동일)

대신에 특정한 문자열이 암호화된 결과인지만을 확인할 수 있기 때문에 원본 내용을 볼 수 없으므로 최근에 많이 사용되고 있다.

 

이를 사용하기 위해

Config 클래스에 Bean 객체로 PasswordEncoder 객체를 다음과 같이 등록해줘야 한다.

 

package com.choonham.security.config;

import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@Log4j2
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity security) throws Exception{
       /**
       * 생략
       **/
    }

}

 

Comments