-
Notifications
You must be signed in to change notification settings - Fork 12
/
08s-allow-and-deny.md.erb
61 lines (39 loc) · 5.45 KB
/
08s-allow-and-deny.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
---
title: Allow와 Deny
slug: allow-and-deny
date: 0008/01/02
number: 8.5
sidebar: true
contents: Allow와 Deny 콜백에 대하여 배운다.|콜백이 호출되는 순서를 이해한다.
paragraphs: 16
---
미티어의 보안시스템 덕분에, 우리는 변경하고자 할 때마다 메서드를 정의하지 않고도 데이터베이스 수정을 제어할 수 있다.
왜냐하면 post를 등록할 때 'post' 메서드를 사용하는 경우, post에 속성을 추가하거나 URL이 이미 등록되어 있을 때 특정한 작업을 해야 하는 것 같은 보조적인 과제를 해야 했기 때문이다.
한 편, post를 변경하거나 삭제할 때에는 새로운 메서드를 만들 필요는 없었다. 단지 사용자가 이런 작업을 할 수 있는 권한을 가지고 있는지를 검사하기만 하면 되었다. 그리고 이 작업은 `allow`와 `deny` 콜백을 사용하여 쉽게 할 수 있었다.
이들 콜백을 사용함으로써 데이터베이스 수정을 선언적으로 처리할 수 있고, 어떤 수정작업을 할 지를 지정할 수 있다. 그리고 이들이 계정 시스템과 통합되어 있다는 사실은 추가 보너스이다.
### 다중 콜백
우리는 필요한 만큼 `allow` 콜백을 정의할 수 있다. 단지 변경이 발생했을 때 그 콜백들 중에서 _최소한 하나만_ true를 리턴하면 된다. 그러므로 브라우저에서 `Posts.insert`가 호출될 때(애플리케이션의 클라이언트 코드이든, 브라우저 콘솔이든 상관없이), 서버는 순서대로 호출하여 그 중 하나가 true를 리턴할 때까지 `insert` 검사를 한다. 만약 하나도 발견하지 못하면 insert는 허용되지 않고, 클라이언트에 `403` 오류를 리턴한다.
유사한 방식으로 하나 이상의 `deny` 콜백을 정의할 수 있다. 만약 이들 가운데 _어느 것_이라도 `true`를 리턴하면, 변경은 취소되고 `403`이 리턴된다. 이 로직은 성공적인 `insert`를 위해서는 하나 또는 그 이상의 `allow`와 모든 `deny` 콜백이 실행된다는 것을 의미한다.
<%= diagram "allow_deny", "주: n/e는 실행되지 않음을 의미한다." %>
다시말하면, 미티어는 콜백 목록을 따라서 실행하면서 처음엔 `deny`로 시작하여 다음엔 `allow`, 그리고 모든 콜백을 그 중 하나가 `true`를 리턴할 때까지 실행한다.
이 패턴의 실제 예제는 두 개의 `allow()` 콜백 - 하나는 post가 현재 사용자의 소유인지를 검사하고, 두 번째는 현재 사용자가 관리자 권한을 가지고 있는지를 검사하는 - 을 가질 수 있다. 만약 현재 사용자가 관리자이면 이는, 그 두 콜백 중의 하나는 적어도 true를 리턴하므로, 어떤 post도 수정할 수 있다는 것을 의미한다.
### 대기시간 보정
데이터베이스를 변경시키는 메서드들(`.update()`와 같은)은 다른 메서드와 마찬가지로 대기시간 보정이 적용된다는 사실을 기억하라. 그래서 만약 브라우저 콘솔에서 독자가 작성하지 않은 post를 삭제하려고 시도하면, post가 로컬 컬렉션의 처리에 따라서 일단 삭제되었다가 서버로부터의 정보 - 사실은 삭제가 되지 않았다는 - 가 오면 다시 나타나는 모습을 볼 수 있을 것이다.
물론 이런 행태가 콘솔에서 구동될 때는 문제가 되지 않는다(결국 사용자가 콘솔에서 시도하여 엉망이 되어도, _자기 브라우저_에서 일어나는 것이니까 문제는 아닌거다). 하지만, 이것이 사용자 인터페이스에서는 일어나지 않도록 확실하게 해 둘 필요는 있다. 이를테면, 삭제할 수 없는 도큐먼트에 대하여는 삭제 버튼이 보여지지 않도록 할 필요는 있는 것이다.
고맙게도, 접근권한에 대한 코드가 클라이언트와 서버에서 공유(이를테면, 라이브러리 함수 `canDeletePost(user, post)`를 작성하여 공유되는 `/lib` 디렉토리에 둘 수 있다)될 수 있기 때문에, 이렇게 코딩하는 것이 보통 과도하게 많은 코드를 요구하는 것은 아니다.
### 서버에서의 접근 권한
접근제어 시스템이 클라이언트로부터 시도되는 데이터베이스 변경시도에 한하여 적용되는 것을 기억하라. 서버에서 미티어는 _모든_ 연산이 허용된다.
클라이언트에서 호출될 수 있는 `deletePost` 미티어 메서드를 서버 쪽에 작성한다면, 누구나 어떤 post든지 삭제할 수 있게 된다. 그러므로 그 메서드 내부에서 사용자의 접근 권한을 검사하지 않으면 안될 것이다.
### Deny 함수를 콜백으로 사용하기
마지막으로, `deny`로 할 수 있는 한 가지 묘기는 이것을 "onX" 콜백으로 사용하는 것이다. 이를테면, 다음과 같은 코드를 사용하면 최종 수정 시간을 얻을 수 있다:
~~~js
Posts.deny({
update: function(userId, doc, fields, modifier) {
doc.lastModified = +(new Date());
return false;
},
transform: null
});
~~~
`deny` 콜백이 *모든* 성공적인 `update`에서 실행되므로, 이 콜백이 실행되면서 구조화된 방식으로 도큐먼트를 변경한다는 것을 알 수 있다.
명백히, 이 기술은 일종의 핵이므로 대신 메서드를 사용하여 update를 수행하기를 원할 수 있다. 그럼에도 불구하고, 이것을 알아 둘 만하며, 언젠가는 일종의 `beforeUpdate` 콜백 같은 것이 이용되기를 바란다.