Role Hierarchy (계층 권한)

  • 권한 A, B, C 가 있고 이중 권한이 A < B < C 로 진행 하고 싶은경우 계층권한을 사용하면 된다.

(사용방법 으로는 SecurityConfig 파일 내부에 🔽)

 // 계층 권한 설정
  @Bean
  public RoleHierarchy roleHierarchy() {
      RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();

      hierarchy.setHierarchy("ROLE_C > ROLE_B > ROLE_A"); // 권한 설정 순위 셋팅 

      return hierarchy;
  }

⇒ 해당 코드를 추가 해주고

// 이제 내부에 어떤 경로에 요청이 왔을때에 어떤 응답을 해줄지 설정 해주면 된다.
// 작성방식은 람다식으로 해주면 된다.
http.authorizeHttpRequests((auth) -> auth
        .requestMatchers("/","/login").permitAll()
        .requestMatchers("/my/**").hasAnyRole("A") // <- A,B,C 모두 들어감
        .requestMatchers("/admin").hasAnyRole("C") // <- C만 들어갈 수 있음
        .anyRequest().authenticated()
);

⇒ SecurityFilterChain 부분에 위와 같은 코드로 사용 가능하다.


해당 정리 내용은 유튜버 개발자 유미님 영상을 보고 정리한 내용 입니다.

좋은 무료 강의가 많아서 다들 한번 방문해 보시는 걸 추천 드려요.

 

 

 

개발자 유미

백엔드 개발자 유미 - 실습 위주 진행 (개념적인 부분은 공식 Docs 참조 및 개인 학습 바랍니다!) - 간혹 댓글 알림이 안오는 경우가 있습니다.

www.youtube.com

 

HttpBasic 인증

로그인 방식

  • formLogin → 지금까지 우리가 한 것 (특정 html login 페이지를 만들어 data 를 서버에 post로 넘기는 방식)
  • httpBasic → 아이디와 비밀번호를 Base64 방식으로 인코딩 한 뒤에 HTTP 헤더에 부착 하여 서버측으로 요청을 보내는 방식 (주로 마이크로서비스 아키텍쳐에서 사용한다.)

⇒ 이 역식 spring 독스 내에 Basic Authentication 문서를 참고하자

⇒ 기존 SecurityConfig 파일 코드에서 🔽

해당 부분으로 변경해주면

⇒ 로그인 페이지 요청 시 🔽

위와 같은 화면으로 로그인 요청을 하게 된다.


해당 정리 내용은 유튜버 개발자 유미님 영상을 보고 정리한 내용 입니다.

좋은 무료 강의가 많아서 다들 한번 방문해 보시는 걸 추천 드려요.

 

 

개발자 유미

백엔드 개발자 유미 - 실습 위주 진행 (개념적인 부분은 공식 Docs 참조 및 개인 학습 바랍니다!) - 간혹 댓글 알림이 안오는 경우가 있습니다.

www.youtube.com

 

InMemory 유저 정보 저장

  • 소수의 유저를 저장하는 좋은 방법
  • 토이프로젝트나 시큐리티 로그인 환경에서 소수의 회원 정보만 필요하고 DB를 따로 투자하기 힘든 경우 InMemory 방식으로 유저를 저장하게 된다.(회원 가입이 없다)

⇒ InMemoryUserDetailsManager 클래스를 통해 유저를 등록하면 된다.

⇒ 해당 부분은 spring 독스의 inMemory 방식을 찾아보자.


csrf enable설정 방법

csrf란?

  • CSRF (Cross Site Request Forgery) 로 요청을 위조하여 사용자가 원하지 않아도 서버측으로 특정 요청을 강제로 보내는 방식
  • 개발 환경에서 Security Config 클래스를 통해 csrf 설정을 disable 설정을 했지만 실제 서비스 환경에서는 csrf 공격을 방지하기위해 csrf disable 설정을 제거하고 추가적인 설정을 진행해야 한다.

(기존 개발 환경에서 🔽)

// 로그인을 하게 되면 csrf 라는 토큰이 필요한데 지금 과정에서는 disable 상태로 두고 개발함
http.csrf((auth) -> auth.disable());

(배포할 시에 수정 코드 🔽)

// 로그인을 하게 되면 csrf 라는 토큰이 필요한데 지금 과정에서는 disable 상태로 두고 개발함
// http.csrf((auth) -> auth.disable());

이렇게 csrf 코드를 주석 처리 해주면 로그인 기능을 사용 할 수 없게 된다.
해당 코드를 주석 처리 하게 되면 enable 처리가 된어 csrf 설정이 진행된다.
enable 처리가 되면 스프링 시큐리티는 CsrfFilter를 통해
POST, PUT, DELETE 요청에 대해 토큰 검증을 진행한다.

(그래서 csrf 토큰을 관리하는 시스템을 구축하여야 한다. 🔽)

(mustache- post 요청에서 설정 기준)

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Login Page</title>
</head>
<body>

login page
<hr>

<form action="/loginProc" method="post" name="loginForm">
    <input id="username" type="text" name="username" placeholder="id"/>
    <input id="password" type="password" name="password" placeholder="password"/>
    <input type="hidden" name="_csrf" value="{{_csrf.token}}"/> 
    <!-- 위의 코드를 집어 넣어 post 요청 코드에 같이 보낸다. -->
    <input type="submit" value="login"/>
</form>

</body>
</html>

⇒ 해당 코드를 바로 실행 하면 csrf 가 null이어서 오류가 발생하게 된다.

application.properties 파일에 추가해주자 🔽

spring.mustache.servlet.expose-request-attributes=true

⇒ 그리고 csrf 설정을 해주면 get 방식의 로그아웃 처리를 post 방식으로 변경해주어야 로그아웃을 할 수 있다.

⇒ 그리고 JWT 방식을 사용할 경우 csrf를 enable 할 정도로 위험 부담이 없다.


해당 정리 내용은 유튜버 개발자 유미님 영상을 보고 정리한 내용 입니다.

좋은 무료 강의가 많아서 다들 한번 방문해 보시는 걸 추천 드려요.

 

 

개발자 유미

백엔드 개발자 유미 - 실습 위주 진행 (개념적인 부분은 공식 Docs 참조 및 개인 학습 바랍니다!) - 간혹 댓글 알림이 안오는 경우가 있습니다.

www.youtube.com

 

세션 설정 (소멸, 중복 로그인, 고정 보호)

  • 사용자가 로그인을 하게 되면 사용자의 정보는 SecurityContextHolder에 의해 서버 세션에 관리된다. → 이번 시간에는 세션의 소멸 시간, 아이디당 세션 생성 개수 설정하는것을 배울 예정이다.

세션 소멸 시간 설정

  • 세션 타임 아웃 설정 → 특정 요청을 수행한 뒤 설정 시간 만큼만 유지

(application.properties 파일에서 🔽)

server.servlet.session.timeout=3000

⇒ 위와 같이 작성하면 3000 초간 로그인이 유지된다.

다중 로그인 설정

  • 동일한 아이디로 다중 로그인을 진행할 경우 설정 방법
  • 공식 문서의 sesstion Management 를 통해 구현 방법이 나와있다.

(SecurityConfig.java 파일에서 🔽)

// 다중 로그인 설정
http.sessionManagement((auth) -> auth
        .maximumSessions(1) // <- 하나의 아이디에 동시접속 수
        .maxSessionsPreventsLogin(true) // <- true: 해당 값을 초과할 경우 새 로그인 차단
        // false: 기존 로그인 아웃 새로그인 진행
);

세션 고정 보호 (해커의 admin 세션 탈취를 보호)

  • sesstionManagement((auth) → auth.sessionFixation().none()); : 로그인 시 세션 정보 변경 안함
  • sesstionManagement((auth) → auth.sessionFixation().newSession()); : 로그인 시 세션 새로 생성
  • sesstionManagement((auth) → auth.sessionFixation().changeSessionId()); : 로그인 시 동일한 세션에 대한 id 변경 ⇒ 주로 이걸 사용하여 보호한다.
// 세션 고정 보호
http.sessionManagement((auth) -> auth.sessionFixation().changeSessionId());

해당 정리 내용은 유튜버 개발자 유미님 영상을 보고 정리한 내용 입니다.

좋은 무료 강의가 많아서 다들 한번 방문해보시는걸 추천 드려요.

 

 

개발자 유미

백엔드 개발자 유미 - 실습 위주 진행 (개념적인 부분은 공식 Docs 참조 및 개인 학습 바랍니다!) - 간혹 댓글 알림이 안오는 경우가 있습니다.

www.youtube.com

 

세션 사용자 아이디 정보 (세션 정보)

  • 회원 id 정보 가져오기
String id = SecurityContextHolder.getContext().getAuthentication().getName();

model.addAttribute("id", id); // <- model에 key 와 value 로 저장하여 프론트에 전달

⇒ 회원 id 의 경우 다음과 같이 간단하게 호출이 가능하다.

  • 회원 등급 정보 가져오기
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
Iterator<? extends GrantedAuthority> iter = authorities.iterator();
GrantedAuthority auth = iter.next();
String role = auth.getAuthority();

model.addAttribute("role", role); // <- model에 key 와 value 로 저장하여 프론트에 전달

⇒ 그런데 role 에 경우 위 처럼 긴 과정을 거쳐 갖고 오게 된다. 이유 좀 알고 싶다.


해당 정리 내용은 유튜버 개발자 유미님 영상을 보고 정리한 내용 입니다.

좋은 무료 강의가 많아서 다들 한번 방문해 보시는 걸 추천 드려요.

 

개발자 유미

백엔드 개발자 유미 - 실습 위주 진행 (개념적인 부분은 공식 Docs 참조 및 개인 학습 바랍니다!) - 간혹 댓글 알림이 안오는 경우가 있습니다.

www.youtube.com

 

로그인 검증 로직

  • 회원 가입을 완료한 회원이 이제 로그인을 할 때 아이디와 비밀번호를 post 요청으로 보내게 된다 그럼 Spring Security 는 DB 에 저장된 회원 정보를 조회 및 검증 하고 서버 세션 저장소에 해당 아이디에 대한 세션을 저장한다.

⇒ Spring Security 에서 제공하는 UserDetails → DTO 와 UserDetailsService → Service 를 각각 구현하는 class 를 생성하여 오버라이딩 한 다음 사용하면 된다.


해당 정리 내용은 유튜버 개발자 유미님 영상을 보고 정리한 내용 입니다.

좋은 무료 강의가 많아서 다들 한번 방문해보시는걸 추천 드려요.

 

 

 

개발자 유미

백엔드 개발자 유미 - 실습 위주 진행 (개념적인 부분은 공식 Docs 참조 및 개인 학습 바랍니다!) - 간혹 댓글 알림이 안오는 경우가 있습니다.

www.youtube.com

 

7. 회원 가입 로직

  • 회원정보를 통해 인증 인가 작업을 진행하기 때문에 사용자로 부터 회원 가입을 진행한 뒤 DB에 회원 정보가 존재 해야한다.

DTO, Entity, Repository 3개의 관계 ??

  1. Entity (엔티티)
    • DB 의 특정 table 에 매핑 되는 자바 객체
package com.example.studysecurity240402.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;

@Entity
@Setter // <-lombok 기능
@Getter // <-lombok 기능
public class UserEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    // id 가 자동 생성 되고 자동 증가 되게 
    private int id;

    private String username;
    private String password;

    private String role;

}

  1. Repository (레포지토리)
    • 레포지토리는 DB 조작 추상화 하는 인터페이스 입니다.
    • Entity 와 관련된 DB 작업을 정의 하고 실행하는 메서드(CRUD)가 제공됩니다.
    • Repository 는 JpaRepository , CrudRepository 같은 것을 상속 받아 사용해야 한다.
package com.example.studysecurity240402.repository;

import com.example.studysecurity240402.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<UserEntity, Integer> {
// JpaRepository 를 상속 받고                    DB와 연동되는 Entity, id의 타입
}

  1. DTO (디티오)
    • Entity 와 클라이언트(프론트) 간의 데이터 전송에 사용되는 객체
    • DTO 는 주로 데이터 전송의 목적에 따라 필요한 필드만 포함하며, 데이터베이스 조작과 관련된 메서드는 포함하지 않습니다.
package com.example.studysecurity240402.dto;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class JoinDTO {
    private String username;
    private String password;
}
// 필요한 필드만 넣어서 사용 DB에 필요한 정보인 id 같은 정보 없이 클라이언트에서 넣어준 정보만 

시큐리티를 사용하여 회원가입 하기

  • Controller 부분
package com.example.studysecurity240402.controller;

import com.example.studysecurity240402.dto.JoinDTO;
import com.example.studysecurity240402.service.JoinService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class JoinController {

    @Autowired
    private JoinService joinService; // <- 서비스 코드 주입 받기

    @GetMapping("/join")
    public String joinP() {
        return "join";
    }

		// 회원 가입 요청이 들어오는 부분
    @PostMapping("/joinProc")
    public String joinProcess(JoinDTO joinDTO) { //<- 프론트에서 전달한 데이터를 받기
        System.out.println(joinDTO.getUsername());

        joinService.joinProcess(joinDTO); // <- service 의 해당 기능에 데이터 전달

        return "redirect:/login"; // <- 잘 작동하면 해당 경로로 리다이렉트
    }
}

  • service 부분
package com.example.studysecurity240402.service;

import com.example.studysecurity240402.dto.JoinDTO;
import com.example.studysecurity240402.entity.UserEntity;
import com.example.studysecurity240402.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

@Service
public class JoinService {

    @Autowired
    private UserRepository userRepository; // <- 레포지토리 주입 받기

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    public void joinProcess(JoinDTO joinDTO) {
        UserEntity data = new UserEntity(); // <-회원 객체를 새로 생성
        data.setUsername(joinDTO.getUsername()); // <- 회원 객체에 id 넣기 
        // 아래가 엔코더를 이용하여 해쉬화
        data.setPassword(bCryptPasswordEncoder.encode(joinDTO.getPassword()));
        // BCrypt를 사용한 해쉬화된 password 를 넣기
        
        data.setRole("ROLE_USER");
				// 회원 티입을 강제로 우리가 넣어준것

        userRepository.save(data); 
        // 레포지토리의 save 기능을 사용하여 data 객체를 넣어주기 
    }
}

⇒ 회원 가입을 해보면

⇒ password 부분은 해쉬화 되어 들어가 있고 나머지는 입력해준 대로 잘 들어가 있는 것을 볼 수 있다.


해당 정리 내용은 유튜버 개발자 유미님 영상을 보고 정리한 내용 입니다.

좋은 무료 강의가 많아서 다들 한번 방문해보시는걸 추천드려요.

 

 

개발자 유미

백엔드 개발자 유미 - 실습 위주 진행 (개념적인 부분은 공식 Docs 참조 및 개인 학습 바랍니다!) - 간혹 댓글 알림이 안오는 경우가 있습니다.

www.youtube.com

 

DB연결

  • 시큐리티 암호화를 사용하려면 일단 DB가 있어야 하니 DB부터 연결해보자
  • 나는 mySQL을 하지 않고 기존 mariaDB 를 사용할 예정

+ Recent posts