본문 바로가기
Programming/Spring Boot

[Spring Boot] Spring Security 설정

by 공부합시다홍아 2024. 5. 29.

스프링 라이브러리 추가

//시큐리티 버전은 스프링버전에 따라 사용방법이 완전히 다릅니다.
//시큐리티 5버전 => 스프링 부트 2버전 (수업)
//시큐리티 6버전 => 스프링 부트 3버전 (문법이 완전 변경되니 주의)
implementation 'org.springframework.boot:spring-boot-starter-security'
//시큐리티 타임리프에서 사용
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
//시큐리티 테스트
testImplementation 'org.springframework.security:spring-security-test'
  • 시큐리티가 처음 설정 되면 모든 요청에 대해서 시큐리가 기본 제공하는 로그인 화면이 보이게 됩니다.
  • 기본아이디는 user / 비밀번호는 console창에 비밀번호를 발급합니다.
  • 로그아웃의 경로는 /logout이 기본이 됩니다.
  • 로그아웃 이후에는 다시 /hello 요청으로 진입이 불가능해 집니다.

🕹️Spring Security Load 시 Console에 비밀번호 발급

이후 모든 요청에 대해서 아래와 같이 기본 제공페이지가 보인다.


스프링 시큐리티 공식 문서
https://docs.spring.io/spring-security/reference/5.7/servlet/configuration/java.html

Spring Security의 패턴 : Builder

Method 의미
anyRequest() 모든 요청
authorizeRequests() Request에 권한 부여
antMatchers() 경로 설정
authenticated() 인증 필요
hasRole() 권한 필요
hasAnyRole() 여러 권한 중 1개 필요
permitAll() 모두 허용
denyAll() 모두 거부

SecurityConfig.JAVA 파일

@Configuration : 해당 파일이 설정 파일임을 명시한다.
@EnableWebSecurity : 시큐리티 설정 파일을 시큐리티 필터에 등록한다.

package com.coding404.demo.security.config;

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.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@EnableWebSecurity 
public class SecurityConfig {
	
	@Bean
	public BCryptPasswordEncoder encoder() {
		return new BCryptPasswordEncoder();
	}
		
	
	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		//csrf토큰 사용x
		http.csrf().disable();
		
		// /logout으로 로그아웃을 시도하고 URL주소를 확인하세요
		//모든 요청에 대해 사용자 인증이 필요합니다.
//		http.authorizeRequests( (authorize) -> authorize.anyRequest().authenticated() );

		//user페이지에 대해서만 사용자 인증이 필요합니다.
//		http.authorizeRequests( (authorize) -> authorize.antMatchers("/user/**").authenticated() );
		
		//user페이지에 대해서 user권한이 필요합니다.
//		http.authorizeRequests( (authorize) -> authorize.antMatchers("/user/**").hasRole("USER")  );
		
		//user페이지에 대해서 user권한이 필요합니다. admin페이지에 대해서 admin권한이 필요합니다.
//		http.authorizeRequests( (authorize) -> authorize.antMatchers("/user/**").hasRole("USER")
//														.antMatchers("/admin/**").hasRole("ADMIN") );
		
		//all페지이는 인증만되면 들어갑니다. user페이지에 대해서 user권한이 필요합니다. admin페이지에 대해서 admin권한이 필요합니다. 
		//나머지 모든 요청은 요청을 허용합니다.
//		http.authorizeRequests( (authorize) -> authorize.antMatchers("/all").authenticated()
//														.antMatchers("/user/**").hasRole("USER")
//														.antMatchers("/admin/**").hasRole("ADMIN")
//														.anyRequest().permitAll() ); 
		
		//all페지이는 인증만되면 들어갑니다. 
		//user페이지에 대해서 user권한 or ADMIN 이필요합니다. 
		//admin페이지에 대해서 admin권한이 필요합니다. 
		//나머지 모든 요청은 요청을 허용합니다.
		http.authorizeRequests( (authorize) -> authorize
								.antMatchers("/all").authenticated()
								.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
								.antMatchers("/admin/**").hasRole("ADMIN")
								.anyRequest().permitAll() ); 
		
		//시큐리티가 제공하는 폼기반 로그인 기능을 사용할 수 있습니다.
		//이후 권한이 없으면 시큐리티는 낚아채서 기본 로그인을 보여줍니다.
		//	http.formLogin( Customizer.withDefaults() );
		
		//사용자가 제공하는 폼기반 로그인 기능을 사용할 수 있습니다.
		http.formLogin().loginPage("/login");

		return http.build();
	}

}
비밀번호 암호화 BCryptPasswordEncoder 객체 

공식 문서
https://docs.spring.io/spring-security/reference/5.7/features/authentication/password-storage.html#authentication-password-storage-bcrypt

스프링 시큐리티에서 비밀번호 단방향 암호화는 필수요소이다.
시큐리티는 비밀번호 암호화 객체 BCryptPasswordEncoder를 제공한다.

쉽게 설명하자면, 우리가 웹 서비스를 이용할 때, 비밀번호를 잊어버려 다시 발급받은 적이 있을 것이다.
그 이유가 바로 스프링 시큐리티의 암호화 객체에 의해 발생한다.
BCryptPasswordEncoder의 암호화로 인하여, 비밀번호를 잊어버렸을 때 해당 비밀번호에 대한 복호화를 수행하지 않는다. 그렇기 때문에 비밀번호를 잊었을 때 다시금 비밀번호를 재설정하는 이유가 이런 것에 있다.

@Bean
public BCryptPasswordEncoder encoder() {
	return new BCryptPasswordEncoder();
}​

위 처럼 BcryptPasswordEncoder 객체를 불러와 Bean으로 등록한다.

@PostMapping("/joinForm")
public String joinForm(UserVO vo) {
    System.out.println(vo.toString());
    String pw = bCryptPasswordEncoder.encode(vo.getPassword());
    vo.setPassword(pw); //비밀번호 암호화

    userMapper.join(vo); //회원가입

    return "redirect:/login";
}

이후 불러온 암호화 객체를 이용해 기존에 사용자가 회원가입시 입력한 비밀번호를 암호화를 진행하고
다시 vo의 비밀번호로 교체해준다.
이 방법을 통해 사용자는 로그인 처리시, 동일하게 암호화된 비밀번호를 찾아 로그인을 할 수 있지만,
잃어버렸을 경우 찾을 수는 없다.


간단하게 구현을 해보기 위해서 Service 영역은 생략하도록 한다.

일단 Controller에는 위와 같이 선언을 해주고, 화면에서 권한을 설정할 수 있도록 처리한다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h3>join</h3>
	
	<form action="joinForm" method="post">
		<input type="text" name="username" placeholder="아이디">
		<input type="password" name="password" placeholder="비밀번호">
		<select name="role">
			<option value="ROLE_USER">user</option>
			<option value="ROLE_ADMIN">admin</option>
			<option value="ROLE_TESTER">tester</option>
		</select>
		
		<input type="submit" value="가입">
	</form>
</body>
</html>

Mapper에서는 DB로 해당 값이 들어갈 수 있도록 처리를 한다.

<insert id="join">
    insert into members values (#{username}, #{password}, #{role})
</insert>

결과

위 사진과 같이 나는 아이디와 비밀번호를 동일하게 입력을 하였음에도 Spring Security 암호화 객체에 의해
비밀번호가 암호화되어 저장된 것을 확인 할 수가 있다.

728x90