Lumen으로 인증을 처음 다루기 시작했을 무렵, 키워드로 Google을 검색하는 것 말고 가장 자주 하게 되는 일은 공식 Authentication 문서를 열어 보는 거예요. 그리고 저처럼, 잔뜩 기대하며 열었다가 결국 잘 모르는 채로 닫게 되죠. Laravel 경험 없이 바로 Lumen을 접한 사람에게는, 이 문서는 생략이 너무 많아서 정말 실마리조차 잡기 어려워요.
인증 구조 전체를 자세히 설명하기 전에, 먼저 이 짧은 한 페이지짜리 Authentication 문서가 결국 무슨 말을 하는 건지 대략 짚어 볼게요.
Authentication Service Provider
이제는 DI(Dependency Injection)가 당연한 시대라, 서비스를 쓰기 전에 먼저 등록하는 건 많은 PHP 개발자에게 거의 반사적인 동작이 됐어요. 그런데 공식 Authentication 문서대로 AuthServiceProvider 등록을 마치고 나서, 다음 단락을 보고 멈칫하는 분이 많을 거예요. 이 의미를 알 듯 말 듯한 코드는 대체 어디서 튀어나온 걸까요?
$this->app['auth']->viaRequest('api', function ($request) {
// Return User or null...
});
단어 하나하나는 알 것 같은데, 뭔가 딱 와닿지가 않아요. 물론 이게 AuthServiceProvider의 boot 메서드 안에 쓰여 있고, 서비스가 시작될 때 동작하는 코드라는 건 알겠어요. 그런데 구체적으로는 무엇을 하고 있는 걸까요?
자, 잠깐만요. 조급해하지 말고, 일단 시야를 넓혀서 큰 의문은 잠시 옆에 놔둘게요. 공식 Authentication 문서 전체가 설명하는 흐름을 쉽게 풀어서 말하면, 대략 이런 느낌이에요:
- 시스템에 인증 서비스를 등록한다.
- 서비스가 시작될 때, 요청을 검사하는 문지기를 준비한다.
- 그 검사 도중에 사용자를 가려낼 필요가 있으면, 반환용 사용자 객체를 준비할 수 있다.
- 인증 미들웨어(auth middleware) 안에서, 준비해 둔 문지기를 호출해 인증 체크를 한다.
여기서는 우선 자주 나오는 의문을 간단한 Q&A 형식으로 답해 볼게요. 자세한 내용과 흐름은 다음 글에서 설명할게요.
Authentication 문서 Q&A
viaRequest 함수는 어디서 온 거예요? 요청을 검사한다는 뜻인가요?
그렇다고도 할 수 있고, 아니라고도 할 수 있어요. 코드의 주석으로 보면, viaRequest는 via Request라기보다 via RequestGuard, 그러니까 요청의 문지기 RequestGuard를 통해 요청을 처리한다는 의미에 가까워요. viaRequest를 호출하면, RequestGuard를 만들기 위한 함수가 등록돼요. 실제 RequestGuard 객체가 만들어지는 건 그 Guard가 처음 resolve될 때이고, 그 전까지는 만들어지지 않아요(이 점은 다음 글에서 자세히 설명할게요).
viaRequest('api', …)의 api는…?
이 api는 지금 만들고 있는 API와는 직접적인 관계가 없어요. 커스터마이즈할 수 있는 auth driver의 키이고, 이론상 어떤 문자열로든 바꿀 수 있어요. 다만 config/auth.php 쪽도 함께 바꾸는 걸 잊지 마세요.
viaRequest(…, callback) 뒤의 callback은…?
여기서의 callback은 사용자 객체를 반환하기 위한 함수예요. 공식 문서의 이 구성에서, 반환된 사용자 객체에는 두 가지 역할이 있어요:
- RequestGuard가, 들어온 요청을 사용자로 해결할지, 아니면 게스트로 처리할지 판단할 수 있게 한다(null을 반환하면 게스트로 간주된다).
$request->user()를 호출했을 때, 이 함수가 동작해 사용자 객체를 가져온다.
app['auth']는 또 어디서 오는 거예요?
아시다시피, ServiceProvider 안의 $this->app은 Lumen Application 객체 그 자체예요. 그리고 app['auth']는 접근될 때 자동으로 생성되는 AuthManager 객체고요. 미리 app['auth']에 접근한 적이 없다면, 여기가 처음 인스턴스화되는 곳일 거예요. 시험 삼아 이 코드 앞뒤에서 isset($this->app['auth'])를 써서 확인해 보세요.
그럼 $this->app['auth']->viaRequest('api', callback)라는 한 줄 전체의 의미는?
간단히 말하면, AuthServiceProvider가 시작될 때 자동으로 만들어진 AuthManager를 통해 RequestGuard의 auth driver를 등록하고, 거기에 사용자를 판별하고 사용자 객체를 가져오기 위한 callback을 넘겨주고 있다는 거예요.
실제로 인증을 하는 코드는 대체 어디에 있어요?
공식 Authentication 문서의 구성에서는 두 군데가 있어요. 첫 번째는 Authenticate Middleware의 handle 함수 안이에요:
if ($this->auth->guard($guard)->guest()) {
return response('Unauthorized.', 401);
}
여기서는 Guard(기본값인 api Guard)를 호출해서, 요청이 게스트로 처리되는지 판단하고, 그렇다면 접근을 거부해요.
두 번째는 AuthServiceProvider의 boot 메서드 안이에요:
$this->app['auth']->viaRequest('api', function ($request) {
// Return User or null...
});
여기서 정의한 사용자 객체를 반환하는 callback이 null을 반환하면, guard($guard)->guest()가 true가 돼요 —— 게스트로 간주돼서 접근이 거부되죠. 반대로 사용자를 반환하면, 요청은 그대로 통과해요.
맺음말
이 글이 공식 Authentication 문서를 이해하는 데 도움이 됐다면, 저로서는 정말 기뻐요. 혹시 아직 의문이 풀리지 않았더라도 괜찮아요. 앞으로의 글에서 인증의 구조 전체를 되도록 자세히 하나씩 풀어 나갈게요. 그때는 또 조금 다른 관점을 전해 드릴 수 있으면 좋겠어요.


