[Spring Security] Default Configuration - Spring Boot (1)

반응형

이번글에서는 Spring Security의 Default Configuartion에 대해 알아보도록 하겠습니다.

1. Unsecured Spring Boot App

이번글에서 사용한 source code는 여기에서 확인할 수 있습니다.

먼저 현재 프로젝트의 구조는 다음과 같습니다.

1-1) dependency

build.gradle

plugins {
    id 'org.springframework.boot' version '2.2.5.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
}

group = 'com.tutorial'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

configurations {
    developmentOnly
    runtimeClasspath {
        extendsFrom developmentOnly
    }
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

test {
    useJUnitPlatform()
}

dependency에는 가장 기본적인 요소들만 포함하였으며, 아직까지 dependcy에 spring-security를 포함시키지 않았습니다.

1-2) templates

view는 spring boot의 thymeleaf를 사용하겠습니다.

아래와 같이 간단히 화면을 구성했습니다.

각 index.html 페이지는 단순히 해당 페이지가 어떠한 페이지인가를 보여주는 화면입니다.

admin/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:insert="fragments.html :: headerfiles"></head>
<body>
<header th:insert="fragments.html :: nav"></header>
<!-- Page content goes here -->
<div class="container">
    <p>This is Admin\Index. Only people with role_admin can see this.</p>
</div>
</body>
</html>

management/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:insert="fragments.html :: headerfiles"></head>
<body>
<header th:insert="fragments.html :: nav"></header>
<!-- Page content goes here -->
<div class="container">
    <p>This is Management\Index. Only people with role_management can see this</p>
</div>
</body>
</html>

profile/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head th:insert="fragments.html :: headerfiles"></head>
<body>
<header th:insert="fragments.html :: nav"></header>
<!-- Page content goes here -->
<div class="container">
    <p>This is User Profile\Index. Only authenticated people can see this</p>
</div>
</body>
</html>

fragement.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<!-- Fragment #1 : Headerfiles contains css and js references -->
<head th:fragment="headerfiles">
    <title>Introduction to SpringBoot Security</title>
    <meta charset="UTF-8"/>
    <link th:href="@{~/bootstrap.min.css}" rel="stylesheet">
    <link th:href="@{~/fontawesome/css/all.css}" rel="stylesheet">
</head>
<body>
<!-- Fragment #2 : Navbar contains nav links -->
<div th:fragment="nav">
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="#">Boot Security</a>

        <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item">
                    <a class="nav-link" href="#" th:href="@{~/index}"><i class="fa fa-home"></i>Home</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#" th:href="@{~/profile/index}">Profile</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#" th:href="@{~/admin/index}">Admin</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#" th:href="@{~/management/index}">Management</a>
                </li>
            </ul>
        </div>
    </nav>
</div>
</body>
</html>

index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:insert="fragments.html :: headerfiles"></head>
<body>
<header th:insert="fragments.html :: nav"></header>
<!-- Page content goes here -->
<div class="container">
    <div class="jumbotron">
        <h1 class="display-4">Hello, Spring Boot Security!</h1>
        <p class="lead">This is the home page of our web application. Anyone can access it, even if they have not signed in.</p>
        <hr class="my-4">
        <p>Using this example, you will become more familiar with Spring Security concepts:)</p>
        <p class="lead">
            <a class="btn btn-primary btn-lg" href="https://spring.io/projects/spring-security" role="button">Learn more about Spring Security</a>
        </p>
    </div>
</div>
</body>
</html>

1-3) controller

controller는 url 호출시 그에 맞는 thymealeaf 페이지를 보여줄 수 있도록 생성했습니다.

AdminController

@Controller
@RequestMapping("admin")
public class AdminController {

    @GetMapping("index")
    public String index(){
        return "admin/index";
    }
}

HomeController

@Controller
@RequestMapping("/")
public class HomeController {
    @GetMapping("index")
    public String index(){
        return "index";
    }
}

ManagementController

@Controller
@RequestMapping("management")
public class ManagementController {

    @GetMapping("index")
    public String index(){
        return "management/index";
    }
}

ProfileController

@Controller
@RequestMapping("profile")
public class ProfileController {

    @GetMapping("index")
    public String index(){
        return "profile/index";
    }
}

추가적으로 아래와 같이 REST API Controller도 하나 생성하겠습니다.

PublicRestApiController

@RestController
@RequestMapping("api/public")
public class PublicRestApiController {

    public PublicRestApiController(){}

    @GetMapping("test1")
    public String test1(){
        return "API Test 1";
    }

    @GetMapping("test2")
    public String test2(){
        return "API Test 2";
    }

}

1-4) launch application

위와 같이 구성된 project를 실행킨 뒤 localhost:8080으로 접근해보겠습니다.

화면 상단에는 Profile / Admin / Management tab이 존재하며, 현재는 어떠한 security도 적용되어 있지 않기 때문에 누구나 해당 tab으로 접근가능한 것을 확인할 수 있습니다.

Profile Tab

Admin Tab

Management Tab

2. Enable Security

이제 위의 spring boot app에 security를 적용해보도록 하겠습니다.

2-1) add security dependency

build.gradle 파일에 아래 2개의 dependency를 추가합니다.

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'

간단히 위의 2개의 dependency만 추가하는 것 만으로도, spring security의 default configration을 사용할 수 있습니다.

view로 thymeleaf를 사용하지 않는 경우에는 첫번째 dependency만 추가하면 됩니다.

2-2) launch security enabled app

이제 동일한 spring boot app을 실행시켜 보겠습니다.

정상적으로 app이 실행된 뒤 console 창을 확인해보면 위와 같이 비밀번호가 하나 임의로 생성되는 것을 확인할 수 있습니다.

이는 spring-security의 defualt configuration이 생성해주는 임의의 password로 사용자는 해당 password를 사용해 app에 접근할 수 있게됩니다.

이 password는 app이 실행될때마다 random으로 생성됩니다.

동일하게 localhost:8080으로 접근해보면 아래와 같이 login page로 redirect 되는 것을 확인할 수 있습니다.

로그인 페이지를 만든적이 없으시다구요..?? 😅

맞습니다. 위의 login 페이지는 spring-security가 생성한 page로 사용자가 생성한 페이지가 아닙니다.

해당 페이지에서 username에는 user를 password에는 앞서 확인한 default password를 입력해야지만 spring boot app으로 입장할 수 있습니다.

• userName : user

• password : 6be3c9c6-af95-461a-a318-17c68d951ebd

2-3) remove generated user & password

만약 직접 정의한 user와 password를 사용하고 싶으면 아래와 같이 application.yml에 입력해 사용합니다.

이후에는 login page에서 위의 username과 password를 입력하면 됩니다.


참고 자료 : https://www.youtube.com/playlist?list=PLVApX3evDwJ1d0lKKHssPQvzv2Ao3e__Q


추천서적

 

스프링5 레시피:스프링 애플리케이션 개발에 유용한 161가지 문제 해결 기법

COUPANG

www.coupang.com

파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음


반응형

댓글

Designed by JB FACTORY