[Spring Security] 계정 생성, 로그인 및 권한 처리

2022. 5. 30. 22:02· BE/Spring
목차
  1. 스프링 시큐리티 설정
  2. 계정 생성, 로그인, 권한 처리 방법
반응형

안녕하세요.

 

Spring Security에 대해서 공부하고 알게되는 내용에 대해서 정리해보려고 합니다.

스스로 간단하게 정리를 하기에 주석에다가 정리를 하였고, 공부하였으니 보기 불편하실 수도 있습니다.

 

이 포스팅은 아래의 강의를 참고하였으니 여기에서 공부하시는 것을 추천드립니다. 

https://inf.run/tcLk

 

[무료] 스프링부트 시큐리티 & JWT 강의 - 인프런 | 강의

스프링부트 시큐리티에 대한 개념이 잡힙니다., - 강의 소개 | 인프런...

www.inflearn.com

 


들어가기 앞서, 프로젝트 개발 환경(필자 기준)

  • 인텔리제이
  • H2 DB
  • Spring Boot 2.7.0
  • maven project

추가한 라이브러리

  • spring-data-jpa : jpa를 편하게 사용하기 위해
  • mustache : 정적 템플릿 사용을 도와줌
  • spring security : 이번 학습 목표. Spring security
  • spring-boot-devtools : Spring 에서 개발을 편하게 해주는 라이브러리
  • h2database : H2 DB와 연결 할 수 있게 도와주는 라이브러리
  • spring-boot-web : Web으로 개발 할 수 있게 도와주는 라이브러리
  • lombok : getter, setter, toString 등 엔티티를 편하게 작성할 수 있게 도와주는 라이브러리

pom.xml 일부 (참고)

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-mustache</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

 

 

스프링 시큐리티 설정

WebSecurityConfigurerAdapter를 상속받아서 설정 파일을 생성하기

@Configuration			// 설정과 관련된 클래스파일임을 알리는 어노테이션
@EnableWebSecurity      // spring Security filter가 Spring filter chain 에 등록
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	...
}

 

 

계정 생성, 로그인, 권한 처리 방법

1. SecurityConfig 파일(WebSecurityConfigurerAdapter을 상속받은 설정 파일)

package com.cos.security1.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;

@Configuration
@EnableWebSecurity      // spring security filter가 Spring filter chain 에 등록

// securedEnabled: @Secured 어노테이션 활성화. @Secured? 특정 URL에 대해서만 간단하게 권한 처리를 할 수 있는 어노테이션
// prePostEnabled: @PreAuthorize, @PostAuthorize 어노테이션 활성화.
// @PreAuthorize: 해당 메소드 진입 전 처리. @PostAuthorize: 해당 메소드 진입 후 처리
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * password 암호화 메소드. 추후 계정 생성 시, 사용함
     * @return
     */
    @Bean
    public BCryptPasswordEncoder encodePw(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception{       // Spring Security 설정
        http.csrf().disable();      // csrf 비활성화

        // URL에 따른 접근 제한 처리
        http.authorizeRequests()
                .antMatchers("/user/**").authenticated()        // URL user : 인증이 되어야 함
                .antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')")      // URL manager : 권한 'ROLE_ADMIN', 'ROLE_MANAGER'가 있어야함
                .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")         // URL admin : 권한 'ROLE_ADMIN'이 있어야함
                .anyRequest().permitAll()      // 위에 명시되지 않은 URL 은 로그인 및 권한 검사 X
                .and()
                .formLogin()
                .loginPage("/loginForm")       // formLogin이 필요한 경우, /login 으로 보낸다.
                .loginProcessingUrl("/login")   // login 주소가 호출이 되면 시큐리티가 낚이채서 대신 로그인을 진행
                .defaultSuccessUrl("/");        // login 성공 시, 보내줄 기본 url


    }
}

 

 

2. User Entity

JPA에 대해 생소하신 분은 이해가 안가실 수 있으니, 위에 남긴 강의를 직접 들어보시는 것을 추천드립니다.

package com.cos.security1.model;

import lombok.*;
import org.hibernate.annotations.CreationTimestamp;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.sql.Timestamp;

@Entity(name="tb_user")
@Data
public class User {
    @Id @GeneratedValue
    private Long id;

    private String username;
    private String password;
    private String email;
    private String role;

    @CreationTimestamp
    private Timestamp createDate;
}

 

 

3. PrincipalDetails

package com.cos.security1.config.auth;

// 시큐리티가 /login url을 낚아채서 로그인을 진행시킴.
// 로그인을 하면 security 전용 session을 만들어준다. (Security ContextHolder)
// 오브젝트 타입 => Authentication 타입 객체
// Authentication 안에 User 정보가 있어야 한다.
// User 오브젝트 타입 => UserDetails 타입 객체

import com.cos.security1.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;

// Security Session 안에 들어갈 수 있는 객체: Authentication
// Authentication 안에 들어갈 수 있는 객체: UserDetails

public class PrincipalDetails implements UserDetails {

    private User user;

    public PrincipalDetails(User user){
        this.user = user;
    }

    // 해당 유저의 권한을 리턴하는 method
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        String role = user.getRole();

        Collection<GrantedAuthority> collect = new ArrayList<>();
        collect.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return role;
            }
        });

        return collect;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    @Override
    // 만료 여부
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    // 잠금 여부
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    // 만료 여부
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    // 회원 사용 여부
    public boolean isEnabled() {
        return true;
    }
}

 

4. PrincipalDetailsService

package com.cos.security1.config.auth;

import com.cos.security1.Repository.UserRepository;
import com.cos.security1.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

// Security 설정에서 loginProcessingUrl("/login")으로 걸었기 때문에
// "/login" 요청이 오면 자동으로 UserDetailsService 타입으로 IoC되어 있는 loadUserByUsername 메소드가 실행된다.
@Service
public class PrincipalDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    // Security Session = Authentication
    // Authentication => UserDetails
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println(username);
        User userEntity = userRepository.findByUsername(username);

        if(userEntity != null){
            return new PrincipalDetails(userEntity);
        }

        return null;
    }
}

 

 

5. IndexController(MainController)

package com.cos.security1.controller;

import com.cos.security1.Repository.UserRepository;
import com.cos.security1.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class IndexController {

    @Autowired
    UserRepository userRepository;

    @Autowired
    BCryptPasswordEncoder encoder;

    ...
    
    // 회원가입 로직
    @PostMapping({"/join"})
    public String join(User user){
        user.setRole("ROLE_ADMIN");

        // 패스워드 암호화를 진행하지 않으면 시큐리티 로그인이 불가능
        String encPw = encoder.encode(user.getPassword());
        user.setPassword(encPw);

        userRepository.save(user);

        return "redirect:/loginForm";
    }

    @GetMapping({"/joinProc"})
    @ResponseBody
    public String joinProc(){
        return "회원가입 완료";
    }

    @Secured("ROLE_ADMIN")          // 이 메소드에 대해서만 특정 권한이 필요할 때 사용 가능
    @GetMapping("/info")
    @ResponseBody
    public String info(){
        return "개인정보";
    }

    @PreAuthorize("hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")       // 메소드 접근 이전에 확인하는 로직
    //@PostAuthorize()                                                      // 메소드 접근 이후에 확인하는 로직
    @GetMapping("/data")
    @ResponseBody
    public String data(){
        return "데이터정보";
    }
}

 

반응형

'BE > Spring' 카테고리의 다른 글

[Spring Security] 페이스북 로그인하기  (0) 2022.06.03
[Spring Security] oAuth2.0 - 구글로 로그인하기  (0) 2022.06.02
[스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술] - 1일차  (0) 2022.05.29
[Spring Boot] 이메일 전송하는 방법  (0) 2022.05.16
[Spring Boot] MongoDB 통신 설정  (0) 2022.05.14
  1. 스프링 시큐리티 설정
  2. 계정 생성, 로그인, 권한 처리 방법
'BE/Spring' 카테고리의 다른 글
  • [Spring Security] 페이스북 로그인하기
  • [Spring Security] oAuth2.0 - 구글로 로그인하기
  • [스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술] - 1일차
  • [Spring Boot] 이메일 전송하는 방법
멍목
멍목
개발 관련 새롭게 알게 된 지식이나 좋은 정보들을 메모하는 공간입니다.
반응형
멍목
김멍목의 개발블로그
멍목
전체
오늘
어제
  • 분류 전체보기 (512) N
    • BE (190)
      • Spring (21)
      • Java (141)
      • Kotlin (6)
      • JPA (22)
    • FE (33)
      • Javascript (16)
      • Typescript (0)
      • React (5)
      • Vue.js (9)
      • JSP & JSTL (3)
    • DB (32)
      • Oracle (22)
      • MongoDB (10)
    • Algorithm (193) N
    • Linux (8)
    • Git (6)
    • etc (42)
    • ---------------------------.. (0)
    • 회계 (4)
      • 전산회계 2급 (4)
    • 잡동사니 (2)

블로그 메뉴

  • 홈
  • 관리

공지사항

인기 글

태그

  • 알고리즘공부
  • 자바 공부
  • 이펙티브자바
  • 이펙티브 자바
  • 알고리즘 공부
  • java 8
  • 자바 테스팅 프레임워크
  • JPA 공부
  • MongoDB 기초부터 실무까지
  • 자기 공부
  • 코테공부
  • 자기개발
  • JPA
  • MongoDB with Node.js
  • Java to Kotlin
  • 자바 개발자를 위한 코틀린 입문
  • 코틀린
  • 코테 공부
  • MongoDB 공부
  • 자기공부
  • 더 자바 Java 8
  • 자기 개발
  • 전산회계 2급 준비
  • 자바공부
  • Oracle
  • junit5
  • 더 자바 애플리케이션을 테스트하는 다양한 방법
  • vue3 공부
  • 프로젝트로 배우는 Vue.js 3
  • Effective Java

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.0
멍목
[Spring Security] 계정 생성, 로그인 및 권한 처리
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.