๐Ÿ Dev Learning/๐ŸงฉSpring

Spring Security ์ ์šฉํ•ด๋ณด๊ธฐ(1)

dev_seong 2023. 6. 19. 02:03

์ด๋ฒˆ์— Spring Boot๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋น„์Šค ํ•˜๋‚˜๋ฅผ ๊ฐœ๋ฐœํ•˜๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ ์™„์ „ ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฑด ์˜ค๋žœ๋งŒ์ด๋ผ ๋‹ค์‹œ ํ•œ๋ฒˆ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ๋ณด๋ฉด์„œ Spring Security๋ฅผ ์ ์šฉํ•˜๋ ค ํ•œ๋‹ค.

 

์ˆœ์„œ : 

- ๊ฐ€์ด๋“œ ์‚ดํŽด๋ณด๊ธฐ

- Spring Boot ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

- Spring Security ํ…Œ์ŠคํŠธ

 

๊ฐ€์ด๋“œ ์‚ดํŽด๋ณด๊ธฐ

Spring์€ ํ™ˆํŽ˜์ด์ง€์—์„œ ๋‹ค์–‘ํ•œ ๊ฐ€์ด๋“œ๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋‚ด๊ฐ€ ํ•„์š”ํ•œ ๊ฐ€์ด๋“œ๋Š” Securing a Web Application์ด๋‹ˆ๊น ํ•œ๋ฒˆ ์‚ดํŽด๋ณธ๋‹ค.

ํ˜„์žฌ ๊ธฐ์ค€(spring security 3.1)์—์„œ๋Š” java 17๋ฒ„์ „ ์ด์ƒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

์ด ๊ฐ€์ด๋“œ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์ธ๊ธฐ๋Šฅ์„ ์•Œ๋ ค์ฃผ๋‹ˆ ๋ฐ”๋กœ git ์ฃผ์†Œ๋กœ ๊ฐ€๋ฉด ๋œ๋‹ค๊ณ  ํ•˜์ง€๋งŒ ๋‚˜๋Š” ํ•œ๋ฒˆ ๋”ฐ๋ผํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

 

 

Spring Boot ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

๋จผ์ € Spring Boot ํ”„๋กœ์ ํŠธ๋Š” Spring์—์„œ ์ œ๊ณตํ•˜๋Š” spring initializr๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ƒ์„ฑํ•˜๊ธฐ ํŽธํ•˜๋‹ค.

์ด๋•Œ ๋‚˜๋Š” gradle์„ ์„ ํƒํ–ˆ๊ณ  ์Šคํ”„๋ง 3.1์„ ์„ ํƒํ•˜์˜€๋‹ค.

์˜์กด ์ชฝ์—์„œ๋Š” Spring Web, Spring Security, Thymeleaf๋ฅผ ์„ ํƒํ•˜์˜€๋Š”๋ฐ ๊ฐ€์ด๋“œ์—์„œ๋Š” ์‹œํ๋ฆฌํ‹ฐ๋Š” ๋’ท๋ถ€๋ถ„์— gradleํŒŒ์ผ์— ์ง์ ‘ ์ถ”๊ฐ€ํ•ด ์ฃผ์ง€๋งŒ ๋‚˜๋Š” ๋ฐ”๋กœ ์ถ”๊ฐ€ํ•˜์˜€๋‹ค.

 

spring web์„ ์ถ”๊ฐ€ํ•œ ์ด์œ  : 

spring boot์—๋Š” ๋‚ด์žฅ tomcat์ด ์žˆ๋‹ค. speing web ์˜์กด์„ฑ ์—†์ด ์Šคํ”„๋ง์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด ์ง์ ‘ ์„ค์ •์„ ํ•ด์ฃผ๊ณ  ๊ตฌ์กฐ์— ๋งž๊ฒŒ ์„ธํŒ…ํ•˜์—ฌ warํŒŒ์ผ๋กœ ๋นŒ๋“œํ•˜๊ณ  ์ง์ ‘ was๋ฅผ ์‹คํ–‰ํ•ด์•ผ์ง€ ์›น์„œ๋น„์Šค๋กœ ๋„์šธ ์ˆ˜ ์žˆ์ง€๋งŒ spring web ์˜์กด์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์ด๋Ÿฐ ๋ฒˆ๊ฑฐ๋กœ์šด ๊ฒƒ๋“ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ธํŒ…์„ ํ•ด์ค€ ์ƒํƒœ๋กœ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ƒฅ ์‹คํ–‰๋ฒ„ํŠผ๋งŒ ๋ˆ„๋ฅด๋ฉด ๋์ด๋‹ค.

 

spring security๋ฅผ ์ถ”๊ฐ€ํ•œ ์ด์œ  : 

๋กœ๊ทธ์ธ, ๊ถŒํ•œ ๋ถ€๋ถ„์„ ๊ฐœ์ธ์ด ๋”ฐ๋กœ ๊ตฌํ˜„ํ•ด๋„ ์•„๋ฌด๋Ÿฐ ๋ฌธ์ œ๋Š” ์—†๋‹ค. ๋Œ€์‹  ์‹ ๊ฒฝ ์“ธ๊ฒŒ ์ •๋ง ๋งŽ์•„์ง€๊ณ  ์‹œ๊ฐ„์ด ๋งŽ์ด ๋“ ๋‹ค.

ํ•˜์ง€๋งŒ spring์ชฝ์—์„œ ์ œ๊ณตํ•˜๋Š” spring security๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๊ฐ„๋‹จํ•œ ์„ค์ •๊ณผ ์ปค์Šคํ…€๋งŒ ํ•ด์ฃผ๋ฉด ํ›Œ๋ฅญํ•œ ๋กœ๊ทธ์ธ, ๊ถŒํ•œ ๋ถ€๋ถ„ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•œ๋‹ค.

์‚ฌ์šฉํ•ด๋ณด๊ณ  ๊ณต๋ถ€ํ•ด์„œ ํ˜ผ์ž์„œ ์‹œ๊ฐ„๋งŒ ์žˆ๋‹ค๋ฉด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ์ •๋„๊นŒ์ง€๋Š” ๊ผญ ํ•ด์•ผ ํ•  ๊ฑฐ ๊ฐ™๋‹ค.

 

Thymeleaf๋ฅผ ์ถ”๊ฐ€ํ•œ ์ด์œ  :

๊ฐ€์ด๋“œ์—์„œ ์ƒ์„ฑํ•˜๊ฒŒ ํ•˜๋Š” html์— ํƒ€์ž„๋ฆฌํ”„ ์ฝ”๋“œ๊ฐ€ ๋“ค์–ด๊ฐ€์žˆ๋‹ค.

 

 

๊ทธ ํ›„ ํ”„๋กœ์ ํŠธ๋ฅผ IDE๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ด์–ด์ฃผ๊ณ  gradle ๋˜๋Š” maven ๋นŒ๋“œ๋ฅผ ํ•ด์ค๋‹ˆ๋‹ค.

์ด๋•Œ java, gradle, maven ๋ฒ„์ „์„ ์ž˜ ํ™•์ธํ•œ๋‹ค.

 

gradle ๋˜๋Š” maven ๋นŒ๋“œ๋ฅผ ํ†ตํ•ด ์˜์กด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ๊ฐ€์ ธ์™”์œผ๋ฉด ์„ฑ๊ณต์ด๋‹ค.

 

 

Spring Security ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„  ํ™”๋ฉด์ด ํ•„์š”ํ•˜๋‹ค ๊ฐ€์ด๋“œ์—์„œ ์ œ๊ณตํ•˜๋Š” ํ™”๋ฉด์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•ด๋ณด์ž.

 

- src/main/java/com/example/securingweb/MvcConfig.java

package com.example.securingweb;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfig implements WebMvcConfigurer {

	public void addViewControllers(ViewControllerRegistry registry) {
		registry.addViewController("/home").setViewName("home");
		registry.addViewController("/").setViewName("home");
		registry.addViewController("/hello").setViewName("hello");
		registry.addViewController("/login").setViewName("login");
	}

}

 

 

- src/main/resources/templates/home.html 

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
    <head>
        <title>Spring Security Example</title>
    </head>
    <body>
        <h1>Welcome!</h1>

        <p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
    </body>
</html>

 

- src/main/resources/templates/hello.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
    <head>
        <title>Hello World!</title>
    </head>
    <body>
        <h1>Hello world!</h1>
    </body>
</html>

์ด๋ ‡๊ฒŒ 2๊ฐœ ์ถ”๊ฐ€ํ•ด๋†“๊ณ  ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•˜๊ณ  localhost:8080 ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ด์„œ ๋“ค์–ด๊ฐ€๋ณด๋ฉด ์‹ ๊ธฐํ•œ ๋กœ๊ทธ์ธ ํ™”๋ฉด์ด ๋ณด์ธ๋‹ค.

์ด๊ฑด Spring Security์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์ด๊ณ  ๋‹ค๋ฅธ url์„ ์ž…๋ ฅํ•ด๋„ http://localhost:8080/login ๋กœ๋งŒ redirect๋˜๋Š”๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์„ค์ •๋„ ์•Œ์•„์„œ ์„ธํŒ…๋˜์–ด์žˆ๋Š” ์ƒํƒœ์ธ๋ฐ ์ด๋•Œ ์กฐ๊ธˆ ์ปค์Šคํ…€์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ์„ค์ •ํ•ด์„œ ์“ฐ๊ฒ ๋‹ค๋Š” ๊ฑธ ์•Œ๋ ค์•ผ ํ•œ๋‹ค.

 

@EnableWebSecurity ๋ฅผ ์ •์˜ํ•จ์œผ๋กœ์จ WebSecurityConfig๋Š” ์‹œํ๋ฆฌํ‹ฐ ๊ด€๋ จ ์„ค์ •์„ ๋‹ด๋‹นํ•˜๋Š” ํด๋ž˜์Šค๋กœ ์ •์˜ํ•˜์˜€๋‹ค.

๊ทธ๋ฆฌ๊ณ  securityFilterChain๋ฉ”์†Œ๋“œ์—์„œ๋Š” SecurityFilterChain์„ returnํ•˜๋Š”๋ฐ ์—ฌ๊ธฐ์„œ /, /home์œผ๋กœ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์€ ์•„๋ฌด๋‚˜ ์ ‘๊ทผ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜์˜€๊ณ  ์ด์™ธ ๋ชจ๋“  url์— ๋Œ€ํ•ด์„œ๋Š” ์ธ์ฆ๋œ ์ƒํƒœ์—ฌ์•ผ์ง€๋งŒ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๋ฅผ ์ฃผ์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ณด๋‚ด๋Š” ์„ค์ •์„ ํ•œ๋‹ค.

 

- src/main/java/com/example/securingweb/WebSecurityConfig.java

package com.example.securingweb;

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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests((requests) -> requests
				.requestMatchers("/", "/home").permitAll()
				.anyRequest().authenticated()
			)
			.formLogin((form) -> form
				.loginPage("/login")
				.permitAll()
			)
			.logout((logout) -> logout.permitAll());

		return http.build();
	}

	@Bean
	public UserDetailsService userDetailsService() {
		UserDetails user =
			 User.withDefaultPasswordEncoder()
				.username("user")
				.password("password")
				.roles("USER")
				.build();

		return new InMemoryUserDetailsManager(user);
	}
}

- src/main/resources/templates/login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
    <head>
        <title>Spring Security Example </title>
    </head>
    <body>
        <div th:if="${param.error}">
            Invalid username and password.
        </div>
        <div th:if="${param.logout}">
            You have been logged out.
        </div>
        <form th:action="@{/login}" method="post">
            <div><label> User Name : <input type="text" name="username"/> </label></div>
            <div><label> Password: <input type="password" name="password"/> </label></div>
            <div><input type="submit" value="Sign In"/></div>
        </form>
    </body>
</html>

 

์œ„ ์ฝ”๋“œ๋ฅผ ๋‹ค ์ถ”๊ฐ€ํ•˜๊ณ  ์‹คํ–‰ํ•ด์„œ localhost:8080์œผ๋กœ ์ ‘๊ทผํ•ด ๋ณด๋ฉด

home.html๋‚ด์šฉ์ด ๋‚˜์˜ค๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ดํผ๋งํฌ๊ฐ€ ๊ฑธ๋ฆฐ here๋ถ€๋ถ„์„ ํด๋ฆญํ•˜๋ฉด localhost:8080/hello ์ชฝ์œผ๋กœ ๋ณด๋‚ด์ง€๋งŒ ์šฐ๋ฆฐ ์„ค์ •์—์„œ /hello๋Š” ์ธ์ฆ๋œ ํšŒ์›๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์— loginํŽ˜์ด์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ง€๊ธˆ์€ ์œ ์ €๊ฐ€ ๋”ฐ๋กœ ์—†๊ธฐ์— WebSecurityConfig์— ์ถ”๊ฐ€๋˜์–ด ์žˆ๋Š” UserDetailsService๋ถ€๋ถ„์— ์ž„์‹œ๋กœ ์ถ”๊ฐ€๋˜์–ด์žˆ๋Š” ํšŒ์›์œผ๋กœ ๋กœ๊ทธ์ธํ•˜์ž(user/password) 

 

๊ทธ ํ›„ hello ์ชฝ์œผ๋กœ ์ ‘๊ทผํ•˜๋ฉด ์ž˜ ์ถœ๋ ฅ๋˜๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋‹ค์Œ ๊ฒŒ์‹œ๊ธ€์—๋Š” ์ข€ ๋” ์ปค์Šคํ…€ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž‘์„ฑํ•ด๋ด์•ผ๊ฒ ๋‹ค.

๐Ÿ˜Ž