= 권한 관리

== 권한 체크 로직

권한 체크는 AuthorizationInterceptor에서 사용자가 가지고 있는 메뉴의 권한 목록을 기반으로 URL Base 로 체크가 되고 있다.

[source,java]
----
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    -- 생략 --
    String httpMethod = request.getMethod();
    String decodedUrl = WebUtil.getDecodedRequestUrl(request, request.getRequestURI().substring(request.getContextPath().length()));

    String queryString = "";
    if (decodedUrl.indexOf('?') > -1) {
        String[] uri = decodedUrl.split("\\?");
        decodedUrl = uri[0];
        queryString = uri[1];
    }

    for (Api api : authMenuList) {
        if (api.getHttpMethod().equals(httpMethod) && checkUriMatch(api.getApiPath(), api.getApiParameters(), decodedUrl, queryString)) {
            return true;
        }
    }
    throw new AuthorizationException("API 권한 없음");
}
----

[source,java]
----
public boolean checkUriMatch(String apiPath, String apiParameters, String decodedUrl, String queryString){
    Map<String, String> requiredParamMap = new HashMap<>();
    if( StringUtils.isNotEmpty(apiParameters)){
        requiredParamMap = Splitter.on('&').trimResults().withKeyValueSeparator('=').split(apiParameters);
    }

    UriTemplate uriTemplate = new UriTemplate(apiPath);
    if ( uriTemplate.matches(decodedUrl) ){
        if( requiredParamMap.size() == 0 ) return true;
        for (Map.Entry<String, String> entry : requiredParamMap.entrySet()) {
            log.debug("Required Param : " + entry.getKey() + "  Value : " + entry.getValue());
            Map<String, String> requestParamMap = getRequestParam(queryString);
            if( !requestParamMap.containsKey(entry.getKey()) || !(entry.getValue()).equals(requestParamMap.get(entry.getKey()))){
                return false;
            }
        }
        return true;
    }else{
        return false;
    }
}
----

== 권한별 메뉴 가져오기

SPA(Single Page Application) 방식으로 최초 메인화면 진입시에 사용자의 권한에 맞는 메뉴 목록을 조회하여 보여준다. +

[source,java]
----
@RestController
@RequestMapping("/auth")
public class MenuController {
    --생략--
    @Operation(summary = "사용자의 권한이 있는 메뉴 조회")
    @GetMapping("/menus-user-auth")
    public List<Menu> getMenuListByAuth() {
        return menuService.getMenuListByAuth(Account.currentUser().getUserId());
    }
    --생략--
}

----

일반 사용자와 시스템 어드민 사용자의 권한 메뉴 조회 서비스가 분리 되어 있다.

[source,java]
----
@Service
public class MenuServiceImpl implements MenuService {
    --생략--
    @Override
    public List<Menu> getMenuListByAuth(String userId) {
        if (Account.currentUser().isSystemAdminUser()) return this.getMenuListByAdminAuth();
        else return this.getMenuListByUserAuth(userId);
    }
    --생략--
}
----

접속중인 상태에서 권한이 변경될 경우 화면 재진입(다시 로그인 또는 브라우저 새로고침)을 통해서 변경된 권한의 메뉴 목록을 다시 로드할 수 있다.

== 권한에 따른 UI Control

SDL에서는 역할관리에서 정의해놓은 역할별로 4개의 권한을 지정할 수 있다. +
최초 화면 진입시 조회한 사용자가 접근 가능한 메뉴 목록에 해당 메뉴에 대한 권한 목록을 함께 가지고 있으며 화면에서 버튼에 directive로 지정함으로써 show/hide 처리를 자동으로 처리한다.

역할관리를 통한 메뉴별 권한 등록

image::front_01_03.png[]
vue 내에서 authorization directive를 통해 버튼 별 권한을 정의한다.(배열로 정의할 경우 여러개 중에 하나만 매칭되도 show처리 됨)

* 여러개의 권한을 둘 경우

[source, html]
----
<button
    type="button"
    class="btn btn-primary btn-sm"
    v-authorization="['UPDATE', 'EXECUTE']"
    @click="onApprWrite"
>
    {{ $t('sdl.approval.label.APPROVE') }}
</button>
----
* 하나의 권한을 둘 경우

[source, html]
----
<button type="button"
    class="btn btn-primary btn-sm"
    v-authorization="'UPDATE'"
    @click="onApprWrite"
>
    {{ $t('sdl.approval.label.APPROVE') }}
</button>
----
* 관리자일 경우는 directive 지정 상관 없이 무조건 show 처리된다.