JAVA/SPRING

특정 제품만 조작이 가능하게끔 권한 주기.

Code Maestro 2023. 5. 20. 17:39
728x90

1. 특정 병원 번호만 어떻게 조작이 가능하게 할 것인가?

이걸 어떻게 구현할지 감이 안 온 나는, 우아한형제들 기술이사 김영한 님의 강의를 평소에 보고 있어서 아래와 같은 조언을 얻었다.

 

  1. 어떤 방법을 사용하든 권한 체크는 서버에서 추가로 해주어야 한다.
  2. 병원의 고유 번호(ex.5764)를 가진 사람이 5764번 병원만 정보를 수정하게끔 할 수 있는가 없는가에 대한 판단도 서버에서 모두 계산해서 클라이언트로 내려주는 것이 좋다.

 

2. 테이블 설계

먼저 아래와 같이 테이블을 설계했다.

 

MemberAuthority 엔티티의 hospitalNo는 병원 번호를 뜻한다. ROLE_MANAGER(병원 관계자) 권한을 가진 사용자만 병원 번호를 가질 수 있다.

 

멤버는 권한에 따라 여러 개의 권한을 가진다. 예를 들어 MANAGER(병원 관계자) 권한은  USER(사용자), MANAGER(병원 관계자) 2개의 권한을 갖게 했다.

 

3. JWT TOKEN

 

프론트에서 서버로 매번 요청할 때마다 doFilter로 Header에서 토큰 정보를 꺼냈다. 이를 기반으로 유저 객체를 생성, Authentication 객체를 만들었고 권한을 부여했다.

 

Spring Security를 활용하여 WebSecurity 설정으로 특정 URL에 들어갈 때 계정에 특정 권한이 있어야지만, 해당 URL에 접근을 허용했다.

 

4. 병원 번호 확인

'병원의 고유 번호(ex.5764)를 가진 사람이 어떻게 자신의 병원만 수정하게 할까?' 고심하던 중, token payload의 정보를 가져올 생각을 했다.

 

병원 MANAGER 권한을 갖은 계정이 클라이언트에서 수정하려는 병원 번호(pk)를 조작하면 다른 병원의 정보 갱신이 가능해진다. 이에 아래와 같이 설계했다.

 

 

1) 먼저 기존의 doFilter를 통해 Manager 권한을 부여. Manager 권한이 필요한 특정 URL에 매번 들어갈 수 있다. (1차 검증)

 

2) 병원 번호를 확인하는 메소드를 아래와 같이 만들었다. 병원 정보를 수정/삭제/추가하려는 경우, 자신이 관리하는 병원 번호인지 확인하기 위해 매번 확인 메소드를 넣었다. (2차 검증)

public void accessManager(
            ServletRequest servletRequest,
            Long hospitalId
    ) {
        Long hospitalNumberInJwt = getHospitalNumberInJwt(servletRequest);
        if (confirmAdmin(hospitalNumberInJwt)) {
            throw new AccessDeniedException("관리자 계정은 관리자 기능을 이용해주세요.");
        } else if (confirmMatchHospitalNumber(hospitalId, hospitalNumberInJwt)) {
            throw new AccessDeniedException("자신의 병원 번호만 조작이 가능합니다.");
        }
    }
    
private boolean confirmAdmin(Long hospitalNumberInJwt) {
    return hospitalNumberInJwt.equals(0L);
}

private boolean confirmMatchHospitalNumber(Long hospitalId, Long hospitalNumberInJwt) {
    return hospitalNumberInJwt.equals(hospitalId)? false: true;
}

 

3) ServletRequest을 통해 토큰의 병원 번호를 꺼낸다. 그리고 프론트 엔드에서 수정 요청한 병원 번호와 DB의 병원 번호가 같은지 확인했다.

 

4) MANAGER 권한이 아닌 ADMIN 권한은 병원 번호 default를 0으로 표시했다. 그렇기에 0이 나오면 ADMIN 권한으로 판단했다.

728x90