Post

Spring boot security 로그인 처리

spring security에서 “사용자”를 나타내는 인터페이스는 UserDetails가 있음. 기본적으로 이를 구현한 User라는 클래스가 제공되고 별다른 설정 없이 inmemory에 계정을 등록하거나 하는 테스트 용도의 코드에서는 자동으로 스프링에서 User 클래스를 사용하는 듯.

아무튼 요구사항에 따라 email이라던지.. id라던지 추가적인 정보를 저장해야 할 것 이므로 UserDetails를 implements한 모델 클래스(Account)로 정의하거나, User 클래스를 extends한 클래스를 정의해도 된다. User 클래스를 확장하는 경우 중복 세션 방지 등의 기능을 자동으로 처리해줘서 편리한 부분이 있다.

1
2
3
4
5
6
7
8
9
10
11
12
@ToString(callSuper=true)
   @Getter
   @Setter
   public class Account extends User {
   private long branchId;
   
  public Account(String username, String password, long branchId,
   Collection<? extends GrantedAuthority> authorities) {
   super(username, password, authorities);
   this.branchId = branchId;
   }
   }

Role과 Authority는 분명히 쓰임이 다르다.
그러나 UserDetails에서는 둘 다 Collection<? extends GrantedAuthority> authorities에 들어간다.
spring security는 이를 구분하기 위해 hasRole()과 hasAutority()로 둘을 구분해서 메서드를 제공하고 있고, Role은 가져올 때 ROLE_ 접두사를 자동으로 붙여준다. 그래서 애초에 authorities에 삽입할 때 Role이면 ROLE_ 접두사를 붙여서 삽입해야 한다.

그리고 로그인에 대한 비즈니스 로직은 UserDetailsService를 구현한 서비스 클래스를 만들어서 처리한다. 예를 들면 loadUserByUsername같은 메서드. DAO를 이용해서 Account를 가져와서 반환해주는 작업. 이거는 DB에서 가져올거라면 꼭 구현해야 하는게 어느 테이블에서 계정 정보를 검색할건지를 못찾으니까. 여기서 DAO를 직접불러서 가져온다.

https://github.com/umbum/convenience-store-POS-system/blob/develop/project/src/main/java/com/umbum/pos/service/AccountService.java

그리고 여기서 Service에서는 DAO(Repository)에 접근해서 Account를 가져올건데, DAO가 다 그렇지만 DB에서 꺼내온걸 객체에 할당할 때 타입 문제에 주의한다. 특히 오라클의 BigDecimal같은 것…

https://github.com/umbum/convenience-store-POS-system/blob/develop/project/src/main/java/com/umbum/pos/repository/AccountRepoImpl.java

AuthenticationProvider는 넘어온 username/password에 해시(Bcrypt)를 적용하고 DB에 있는 정보랑 일치하는지 판단해서 인가하는 작업을 처리한다. 따라서 이러한 작업에 대한 커스터마이징(예를 들면 password 뿐만 아니라 지점 번호도 검증을 할거라던가.)이 필요하지 않다면 구현하지 않고 그냥 스프링에서 처리하도록 놔둬도 된다.

로그인 성공 / 실패에 대한 콜백을 커스터마이징 해야 한다면 AuthenticationSuccessHandler / AuthenticationFailureHandler

제일 기본적인 예제

좀 더 커스텀한 예제. AuthenticationProvider

다음 설정을 안하면 모든 POST가 /login 쪽으로 포워딩되니까 개발 시에는 다음 설정을 수행해주고, 실제 서비스 시에는 csrf token을 페이지에 hidden으로 넣어서 줄 것.

1
http.csrf().disable();

로그인한 사용자 정보를 가져오기

https://github.com/thymeleaf/thymeleaf-extras-springsecurity

타임리프에서 현재 로그인한 유저 이름을 가져온다던가, 로그인한 유저 권한을 가져온다던가, ROLE_에 따라서 어떤 DOM을 띄워줄지 말지 등등을 컨트롤하려면 이걸 쓴다.

백엔드에서 현재 로그인한 사용자 정보 가져오기

ACCOUNT, AUTHORITY 테이블 예제

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE ACCOUNT(
   USERNAME VARCHAR2(32) NOT NULL,
   PASSWORD VARCHAR2(128) NOT NULL,
   BRANCH\_ID NUMBER(18) NOT NULL,
   CONSTRAINT PK\_ACCOUNT PRIMARY KEY(USERNAME)
   );
   CREATE TABLE AUTHORITY(
   USERNAME VARCHAR2(32) NOT NULL,
   AUTHORITY VARCHAR2(32) NOT NULL,
   CONSTRAINT FK\_AUTHORITY FOREIGN KEY(USERNAME)
   REFERENCES ACCOUNT(USERNAME)
   );
This post is licensed under CC BY 4.0 by the author.