관리자 화면과 협력사 화면을 각각 만들게 되면서 로그인을 하나로 할지 물음이 나왔다.
Table of contents
Open Table of contents
두 쪽이 무엇을 하는지 봤다
관리자는 전체를 본다. 회원 정보와 주문과 정산과 config 까지 다 닿는다. 협력사는 WHERE partner_no = ? 로 자기 것만 본다. 다른 협력사 것은 못 본다.
권한 범위가 크게 달랐고 겹치는 부분이 거의 없었다. 이 차이가 판단의 근거가 됐다.
합칠 때와 나눌 때
합치면 로그인 코드를 한 번만 만든다. password_hash 와 password_verify 로 비밀번호를 다루는 자리가 하나다. 잠금과 이력 남기기도 거기서 한다. 관리자가 협력사 화면을 볼 일이 있을 때 다시 로그인하지 않아도 되는 것도 이점이었다.
나누면 권한 실수의 범위가 좁아진다. 하나로 두면 권한 확인 if 하나를 잘못 썼을 때 협력사가 관리자 화면에 들어간다. 나누면 애초에 그 화면이 다른 자리에 있다. 협력사 계정이 유출됐을 때 닿는 범위도 그 안에 갇힌다.
나누기로 했다
grep -rn 으로 두 쪽이 닿는 표를 세어 보니 겹치는 것이 적었다. 밖에서 쓰는 계정과 안에서 쓰는 계정을 섞지 않는 편이 낫다는 것도 이유였다.
접근할 수 있는 자리도 나눠서 관리자 화면은 사내망이나 VPN 에서만 열리게 했다. 앞단의 allow from 만으로 막지 않고 애플리케이션에서 REMOTE_ADDR 도 확인했다. 설정 하나가 빠지면 그대로 열리기 때문이다.
로그인 코드 자체는 비슷해서 AuthCore 로 그 부분만 공통으로 뒀다.
class AuthCore {
public function attempt($table, $id, $pw);
public function lockCheck($table, $id);
public function logAttempt($table, $id, $ok, $ip);
}
attempt 와 lockCheck 와 logAttempt 가 하는 일은 같다. $table 이 admin_user 냐 partner_user 냐만 다르다. 로그인을 나누는 것과 로그인 코드를 두 벌 쓰는 것은 다른 이야기였다.
세션도 갈라야 했다. 같은 도메인이면 쿠키가 그대로 공유된다. cookie_path 를 /admin 과 /partner 로 나눠 서로의 세션을 안 보게 했다.
대신 보기를 만들었다
나누고 나니 문의를 처리할 때 관리자가 협력사 화면을 봐야 하는 경우가 생겼다. 협력사 비밀번호를 물어보는 것은 안 될 일이다. password_hash 로 넣어 둔 값은 되돌릴 수도 없다. 그래서 viewAs 를 만들었다.
public function viewAs($partnerNo) {
if (!$this->admin->isLogin()) { show_404(); }
$this->session->set_userdata('view_as_partner', $partnerNo);
$this->session->set_userdata('view_as_admin', $this->admin->id());
redirect('/partner/');
}
isLogin 으로 관리자인지 먼저 보고 set_userdata 에 담은 뒤 redirect 한다. 화면 위에 대신 보는 중이라는 표시를 두고 그동안에는 POST 를 막았다. 보는 것만 되고 고치는 것은 안 되게 한 것인데 누가 고쳤는지 흐려지는 것을 막으려는 것이었다. view_as_admin 에 담긴 관리자 번호로 누가 언제 어느 협력사 화면을 봤는지도 남겼다.
몇 달 뒤 협력사 계정 하나가 유출된 일이 있었다. 그 계정으로 닿을 수 있는 것이 그 협력사 자료뿐이었다. 하나로 돼 있었으면 권한 확인 코드 하나에 기대야 했다. 나눠 두니 그 코드가 틀렸어도 화면 자체가 다른 자리에 있었다. 막는 것을 한 겹만 두지 않은 것이 그때 값을 했다.
정리
- 로그인을 합칠지 나눌지는 권한 범위가 얼마나 다른지로 가른다
- 합치면 코드가 하나지만 권한 확인
if하나에 전부가 걸린다 password_hash로 넣은 값은 되돌릴 수 없으니 대신 보기가 필요하다- 밖에서 쓰는 계정과 안에서 쓰는 계정을 섞지 않는다
- 앞단의
allow from과 애플리케이션의REMOTE_ADDR둘 다에서 막는다 - 같은 도메인이면
cookie_path를/admin과/partner로 갈라야 한다 - 로그인을 나누는 것과
AuthCore를 두 벌 쓰는 것은 다르다 - 대신 봐야 하면 대신 보기를 만들고 비밀번호를 묻지 않는다
- 대신 보는 동안은
POST를 막고view_as_admin을 기록에 남긴다