Dev/SpringBoot

5. [springboot] Spring Security 간단 권한관리 예제

VIPeveloper 2020. 6. 8. 13:44
728x90
반응형

1. 서론

- 스프링 시큐리티 공부하던 도중 간단하게 권한 부여하는 방법을 예제로 구현해보고자 포스팅하게 되었습니다.

 

- 이 포스팅을 잘 보게 될 경우 간단한 권한관리를 알 수 있게 됩니다.

2. 본론

 

전체 프로젝트 구조

- 먼저, 간단하게 컨트롤러 구성부터 해보겠습니다.

package com.example.springsecurity.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@Slf4j
public class HomeController {

    @GetMapping("/")
    public String home(Model model){
        log.info("home controller");
        return "home";
    }
    @GetMapping("/user")
    public String dispUser(Model model){
        log.info("home controller");
        return "/user/user";
    }
    @GetMapping("/manager")
    public String dispManager(Model model){
        log.info("home controller");
        return "/user/manager";
    }
    @GetMapping("/admin")
    public String dispAdmin(Model model){
        log.info("home controller");
        return "/user/admin";
    }
}

- 각각의 컨트롤러는 해당 html에 매핑되어 권한별로 표시해줄 수 있게 됩니다.

 

- home.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="https://www.thymeleaf.org"
      xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5 ">
<head>
    <title>Spring Security Example</title>
</head>
<body>
<h1>Welcome!</h1>
​
<p>Click <a th:href="@{/user}">user</a> to see a greeting.</p>
<p>Click <a th:href="@{/manager}">manager</a> to see a greeting.</p>
<p>Click <a th:href="@{/admin}">admin</a> to see a greeting.</p>
</body>
</html>

유저페이지

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>유저페이지</h1>
</body>
</html>

매니저 페이지

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>매니저페이지</h1>
</body>
</html>

어드민 페이지

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>어드민페이지</h1>
</body>
</html>

 

- 시큐리티 환경 구성하기

package com.example.springsecurity.security;

import lombok.extern.slf4j.Slf4j;
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;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity  // 이거 안해줘서 그동안 계속 안됬었음
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {

        String password = passwordEncoder().encode("1111");

        auth.inMemoryAuthentication().withUser("user").password(password).roles("USER");
        auth.inMemoryAuthentication().withUser("manager").password(password).roles("MANAGER");
        auth.inMemoryAuthentication().withUser("admin").password(password).roles("ADMIN");
    }

    @Bean
    // BCryptPasswordEncoder는 Spring Security에서 제공하는 비밀번호 암호화 객체입니다.
    // Service에서 비밀번호를 암호화할 수 있도록 Bean으로 등록합니다.
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/user").hasRole("USER")
                .antMatchers("/manager").hasRole("MANAGER")
                .antMatchers("/admin").hasRole("ADMIN")
                .anyRequest().authenticated()
            .and()
                .formLogin();
    }


}

- @Configuration, @EnableWebSecurity 어노테이션을 추가해줘서 이게 시큐리티 설정을 해주는 클래스다~라는 것을 알려주는 것 같습니다.

 

- AuthenticationManagerBuilder 객체 오버 라이딩은 가상의 계정을 만들어 주는 설정입니다.

- password는 passwordEncoder()에 의해 인코딩 되고, 비밀번호는 간단하게 '1111' string으로 설정하였습니다.

- 그 후 각각의 계정을 생성하고, 권한을 부여해주었습니다.

 

- Bean을 주입한 PasswordEncoder는 BCryptPasswordEncoder라는 스프링 시큐리티 자체 인코딩을 이용하여 암호화해줍니다.

 

- HttpSecurity 객체 오버 라이딩은 시큐리티 설정의 핵심 부분으로, 각각의 권한에. antMatchers("controller mapping url명"). permitAll()이나, hasRole("권한명")으로 연결되어있습니다.

- .anyRequest(). authenticated()는 이것을 제외한 모든 url 연결에는 인증이 사용됩니다.

- .and() 로 묶어주었고, .formLogin() 을 사용하여 스프링 시큐리티에서 제공하는 기본 form Login 형태를 이용하도록 해주었습니다.

 

3. 결과

 

home.html입니다. 잘 나오네요

 

어떤 것을 눌러도 인증하기 위한 로그인 폼이 뜨는 것을 확인할 수 있습니다.

 

user, 1111로 로그인을 해보면

유저 페이지는 잘 들어와 졌지만 

manager 페이지에서는 403 에러가 발생한 것을 볼 수 있습니다.

 

- manager, admin에서도 각각의 페이지는 잘 접속이 되지만 다른 권한을 가지고 있는 경우 접속이 안 되는 것을 확인할 수 있습니다!

 

** 참고사항으로, 다른 admin, manager로 권한 차별성을 실험해보고 싶으실 때, /logout을 url에 직접 입력하여 기존 user를 logout 시켜주어야 합니다! **

 

 

4. 마무리

 

- 이상으로 각 권한별 접근 가능 페이지를 나누어보는 간단한 예제를 구성해보았습니다.

728x90
반응형