인증
번역일: 2026년 7월 2일
인증
- 소개
- 인증 빠른 시작
- 수동으로 사용자 인증하기
- HTTP Basic 인증
- 로그아웃
- 비밀번호 확인
- 커스텀 가드 추가
- 커스텀 사용자 프로바이더 추가
- 자동 비밀번호 재해싱
- 소셜 인증
- 이벤트
소개
많은 웹 애플리케이션은 사용자가 로그인할 수 있는 인증 기능을 제공합니다. Laravel은 이 기능을 직접 구현하지 않아도 되도록, 인증과 관련된 다양한 도구를 기본으로 제공합니다.
Laravel의 인증 시스템은 크게 두 가지 개념으로 구성됩니다: **가드(guard)**와 프로바이더(provider). 가드는 각 요청마다 사용자를 어떻게 인증할지를 정의합니다. 예를 들어 기본 session 가드는 세션 스토리지와 쿠키를 이용해 상태를 유지합니다.
프로바이더는 영속 저장소(데이터베이스 등)에서 사용자를 어떻게 조회할지를 정의합니다. Laravel은 Eloquent와 데이터베이스 쿼리 빌더를 기본으로 지원하며, 필요에 따라 커스텀 프로바이더도 추가할 수 있습니다.
애플리케이션의 인증 설정 파일은 config/auth.php에 있습니다. 여러 가드와 프로바이더를 조합하는 방법이 잘 문서화되어 있으니, 필요할 때 직접 살펴보세요.
NOTE
가드와 프로바이더를 권한 부여(authorization)와 혼동하지 마세요. 권한 부여는 특정 행동의 허용 여부를 다루며, 별도의 권한 부여 문서에서 설명합니다.
스타터 킷
인증 시스템을 빠르게 구축하고 싶다면, Laravel의 스타터 킷을 활용하는 것이 가장 좋은 출발점입니다. Laravel Breeze는 로그인, 회원가입, 비밀번호 재설정, 이메일 인증, 비밀번호 확인 등 핵심 인증 기능 전체를 Blade와 Tailwind CSS로 구현해 줍니다.
좀 더 풍부한 기능을 원한다면 Laravel Jetstream을 고려해보세요. Jetstream은 Breeze의 기능에 더해, Livewire나 Inertia 기반의 UI, 2단계 인증, 팀 관리 등 고급 기능을 제공합니다. Jetstream은 내부적으로 Laravel Fortify를 사용하는데, Fortify는 헤드리스 인증 백엔드로서 프론트엔드와 무관하게 인증 기능을 처리합니다.
NOTE
스타터 킷에 대한 자세한 내용은 스타터 킷 문서를 참고하세요.
데이터베이스 고려사항
Laravel은 기본적으로 app/Models 디렉터리에 App\Models\User Eloquent 모델을 포함합니다. 이 모델은 기본 Eloquent 인증 드라이버와 함께 사용됩니다. Eloquent를 사용하지 않는 경우에는 Laravel 쿼리 빌더를 활용하는 database 인증 프로바이더를 선택할 수 있습니다.
App\Models\User 모델의 데이터베이스 스키마를 작성할 때, password 컬럼의 길이는 최소 60자 이상이어야 합니다. 255자로 설정하는 것이 무난합니다. 기본 마이그레이션 파일은 이미 이 조건을 충족하는 users 테이블을 생성합니다.
또한 users 테이블에 remember_token 컬럼(100자 문자열, nullable)이 있는지 확인하세요. 이 컬럼은 "로그인 상태 유지" 기능을 사용할 때 토큰을 저장하는 데 쓰입니다. 마찬가지로 기본 마이그레이션에 이미 포함되어 있습니다.
에코시스템 개요
Laravel은 인증과 관련된 여러 패키지를 공식으로 제공합니다. 본격적으로 시작하기 전에, 전체 생태계를 간략히 살펴보고 각 패키지의 용도를 파악해두면 도움이 됩니다.
Laravel Breeze: 로그인, 회원가입, 비밀번호 재설정, 이메일 인증, 비밀번호 확인 등 모든 인증 기능을 Blade + Tailwind CSS로 빠르게 구성해주는 경량 스타터 킷입니다. 처음 Laravel을 시작하거나, 간단한 프로젝트에 적합합니다.
Laravel Jetstream: Breeze보다 더 많은 기능을 제공하는 풍부한 스타터 킷입니다. Livewire 또는 Inertia.js(Vue/React) 기반 UI, 2단계 인증, 세션 관리, API 토큰 지원(Laravel Sanctum 사용), 팀 관리 기능을 포함합니다. 규모 있는 프로젝트나 SaaS 형태의 애플리케이션에 적합합니다.
Laravel Fortify: 헤드리스(UI 없는) 인증 백엔드입니다. 로그인, 회원가입, 비밀번호 재설정, 2단계 인증 등의 기능을 라우트와 컨트롤러 형태로 제공하지만, 뷰는 포함하지 않습니다. Jetstream이 내부적으로 Fortify를 사용하며, 직접 커스텀 프론트엔드를 구축할 때 유용합니다.
Laravel Sanctum: API 토큰 및 SPA(싱글 페이지 애플리케이션) 인증을 위한 패키지입니다. 모바일 앱이나 Nuxt, Next.js 같은 SPA와 Laravel 백엔드를 연동할 때 주로 사용됩니다.
Laravel Passport: OAuth2 프로토콜을 완전히 구현한 패키지입니다. 외부 서비스에 API 접근 권한을 부여하는 OAuth2 서버가 필요할 때 사용합니다. Sanctum보다 복잡하지만, 그만큼 강력한 OAuth2 기능을 제공합니다.
NOTE
대부분의 신규 프로젝트에는 Breeze 또는 Jetstream이 권장됩니다. API만 제공하는 백엔드라면 Sanctum을 먼저 고려하세요. OAuth2가 반드시 필요한 경우에만 Passport를 선택하세요.
인증 빠른 시작
스타터 킷 설치
인증 기능을 갖춘 애플리케이션을 빠르게 만들고 싶다면 Laravel 스타터 킷을 사용하세요. Breeze나 Jetstream을 설치하면 로그인, 회원가입 등 전체 인증 UI와 라우트, 컨트롤러가 자동으로 구성됩니다.
스타터 킷을 이미 설치했다면, 이후 섹션에서 인증 관련 클래스를 직접 다루는 방법을 계속 살펴보세요.
인증된 사용자 조회
스타터 킷을 설치한 후, 현재 로그인한 사용자를 코드에서 가져오는 방법을 알아보겠습니다. 요청을 처리하는 도중에는 Auth 파사드의 user() 메서드로 현재 사용자를 조회할 수 있습니다:
use Illuminate\Support\Facades\Auth;
// 현재 인증된 사용자 조회
$user = Auth::user();
// 현재 인증된 사용자의 ID 조회
$id = Auth::id();또는 사용자가 인증된 상태라면, Illuminate\Http\Request 인스턴스를 통해서도 접근할 수 있습니다. 컨트롤러 메서드에서 타입 힌트로 Request를 주입하면, 어디서든 $request->user()를 사용할 수 있습니다:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class FlightController extends Controller
{
/**
* 예약된 항공편 목록을 반환합니다.
*/
public function index(Request $request): mixed
{
return $request->user();
}
}사용자 인증 여부 확인
현재 요청을 보낸 사용자가 로그인 상태인지 확인하려면 Auth 파사드의 check() 메서드를 사용합니다. 인증된 경우 true를 반환합니다:
use Illuminate\Support\Facades\Auth;
if (Auth::check()) {
// 사용자가 로그인된 상태입니다.
}NOTE
check() 메서드로도 인증 여부를 확인할 수 있지만, 라우트나 컨트롤러에 접근하기 전에 인증 여부를 검사할 때는 미들웨어를 사용하는 것이 일반적입니다. 자세한 내용은 라우트 보호 섹션을 참고하세요.
라우트 보호
라우트 미들웨어를 사용하면 인증된 사용자만 특정 라우트에 접근할 수 있도록 제한할 수 있습니다. Laravel에는 Illuminate\Auth\Middleware\Authenticate 클래스를 가리키는 auth 미들웨어가 기본으로 등록되어 있습니다:
Route::get('/flights', function () {
// 인증된 사용자만 접근 가능합니다.
})->middleware('auth');미인증 사용자 리디렉션
auth 미들웨어가 인증되지 않은 사용자를 감지하면, 자동으로 login이라는 이름의 라우트로 리디렉션합니다. 이 동작은 애플리케이션의 bootstrap/app.php 파일에서 변경할 수 있습니다:
use Illuminate\Http\Request;
use Illuminate\Auth\Middleware\Authenticate;
->withMiddleware(function (Middleware $middleware) {
$middleware->redirectGuestsTo('/login');
// 클로저를 사용할 수도 있습니다.
$middleware->redirectGuestsTo(fn (Request $request) => route('login'));
})가드 지정
auth 미들웨어를 등록할 때 어떤 가드를 사용할지 명시할 수 있습니다. 지정하는 가드 이름은 config/auth.php의 guards 배열에 정의된 키와 일치해야 합니다:
Route::get('/flights', function () {
// 인증된 사용자만 접근 가능합니다.
})->middleware('auth:admin');로그인 횟수 제한
Laravel Breeze 또는 Jetstream 스타터 킷을 사용하는 경우, 로그인 시도에 자동으로 횟수 제한(rate limiting)이 적용됩니다. 일정 횟수 이상 로그인에 실패하면 1분 동안 로그인이 차단됩니다. 이 제한은 사용자의 이메일(또는 아이디)과 IP 주소를 조합하여 사용자별로 독립적으로 적용됩니다.
NOTE
애플리케이션의 다른 라우트에도 횟수 제한을 적용하고 싶다면 라우트 횟수 제한 문서를 참고하세요.
수동으로 사용자 인증하기
스타터 킷을 반드시 사용할 필요는 없습니다. 스타터 킷 없이 인증 로직을 직접 구현하려면 Laravel의 인증 클래스를 직접 사용하면 됩니다.
Auth 파사드의 attempt() 메서드를 활용하겠습니다. 먼저 Auth 파사드를 임포트하세요. 다음 예시는 전형적인 로그인 컨트롤러입니다:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
/**
* 인증 시도를 처리합니다.
*/
public function authenticate(Request $request): RedirectResponse
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
return redirect()->intended('dashboard');
}
return back()->withErrors([
'email' => '입력하신 정보와 일치하는 계정을 찾을 수 없습니다.',
])->onlyInput('email');
}
}attempt() 메서드는 키-값 쌍의 배열을 첫 번째 인수로 받습니다. 배열의 값을 기준으로 데이터베이스에서 사용자를 조회하며, 위 예시에서는 email 컬럼으로 사용자를 찾습니다. 사용자를 찾으면 데이터베이스에 저장된 해시된 비밀번호와 입력된 password 값을 비교합니다. password 값은 직접 해싱하지 않아도 됩니다. Laravel이 자동으로 처리합니다. 두 값이 일치하면 인증 세션이 시작됩니다.
인증이 성공하면 request->session()->regenerate()를 호출해 세션 ID를 재생성하는 것을 잊지 마세요. 이는 세션 고정 공격(session fixation)을 방지하기 위한 중요한 보안 조치입니다.
attempt() 메서드는 인증 성공 시 true, 실패 시 false를 반환합니다.
intended() 메서드는 인증 미들웨어에 의해 차단되기 전에 접근하려 했던 URL로 리디렉션합니다. 해당 URL이 없을 경우를 대비해 기본값(예: dashboard)을 지정할 수 있습니다.
추가 조건으로 인증하기
이메일과 비밀번호 외에 다른 조건을 인증에 추가할 수도 있습니다. attempt() 메서드에 전달하는 배열에 원하는 조건을 추가하면 됩니다. 예를 들어, 사용자가 "활성화" 상태인지도 함께 확인하려면 다음과 같이 작성합니다:
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// 인증 성공...
}복잡한 조건이 필요할 경우 클로저를 배열에 포함시킬 수도 있습니다. 이 클로저는 쿼리 인스턴스를 받아 원하는 조건을 추가할 수 있습니다:
use Illuminate\Database\Eloquent\Builder;
if (Auth::attempt([
'email' => $email,
'password' => $password,
fn (Builder $query) => $query->has('activeSubscription'),
])) {
// 인증 성공...
}WARNING
위 예시에서 email은 필수 옵션이 아닙니다. 단지 예시로 사용한 것입니다. 실제 데이터베이스의 "사용자명"에 해당하는 컬럼 이름을 자유롭게 사용하세요.
attemptWhen() 메서드를 사용하면 실제 인증을 시도하기 전에 잠재적 사용자를 대상으로 추가 검사를 수행할 수 있습니다. 두 번째 인수로 전달된 클로저는 사용자 인스턴스를 받아 true 또는 false를 반환해야 합니다:
if (Auth::attemptWhen([
'email' => $email,
'password' => $password,
], function (User $user) {
return $user->isNotBanned();
})) {
// 인증 성공...
}특정 가드 인스턴스 접근
Auth 파사드의 guard() 메서드를 사용하면 인증 시 어떤 가드를 사용할지 지정할 수 있습니다. 이를 통해 애플리케이션의 서로 다른 영역(예: 일반 사용자 / 관리자)에 대해 독립적인 인증을 관리할 수 있습니다.
guard() 메서드에 전달하는 가드 이름은 config/auth.php에 정의된 가드와 일치해야 합니다:
if (Auth::guard('admin')->attempt($credentials)) {
// 관리자 인증 성공...
}사용자 기억하기
많은 애플리케이션이 로그인 폼에 "로그인 상태 유지" 체크박스를 제공합니다. 이 기능을 구현하려면 attempt() 메서드의 두 번째 인수로 true를 전달하면 됩니다.
이 값이 true이면 Laravel은 사용자가 수동으로 로그아웃할 때까지 인증 상태를 영구적으로 유지합니다. users 테이블에 remember_token 컬럼이 있어야 하며, 이 컬럼에 토큰을 저장합니다. 기본 Laravel 마이그레이션에는 이미 포함되어 있습니다:
use Illuminate\Support\Facades\Auth;
if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {
// 사용자가 기억됩니다...
}"로그인 상태 유지" 기능으로 인증된 사용자인지 확인하려면 viaRemember() 메서드를 사용합니다:
use Illuminate\Support\Facades\Auth;
if (Auth::viaRemember()) {
// 이 사용자는 "로그인 상태 유지" 쿠키로 인증되었습니다.
}기타 인증 방법
사용자 인스턴스로 인증하기
이미 가져온 사용자 인스턴스로 현재 사용자를 인증해야 할 때는 login() 메서드를 사용합니다. 전달하는 객체는 Illuminate\Contracts\Auth\Authenticatable 컨트랙트를 구현해야 합니다. Laravel의 App\Models\User 모델은 이미 이 컨트랙트를 구현합니다. 이 방식은 회원가입 직후 자동 로그인 처리 등에 유용합니다:
use Illuminate\Support\Facades\Auth;
Auth::login($user);login() 메서드의 두 번째 인수로 불리언 값을 전달하면 "로그인 상태 유지" 여부를 지정할 수 있습니다:
Auth::login($user, $remember = true);특정 가드를 사용하고 싶을 때는 다음과 같이 작성합니다:
Auth::guard('admin')->login($user);사용자 ID로 인증하기
데이터베이스의 primary key를 사용해 사용자를 인증하려면 loginUsingId() 메서드를 사용합니다:
Auth::loginUsingId(1);두 번째 인수로 "로그인 상태 유지" 여부를 지정할 수 있습니다:
Auth::loginUsingId(1, remember: true);일회성 인증
once() 메서드를 사용하면 세션이나 쿠키를 사용하지 않고 단 한 번의 요청에만 사용자를 인증합니다. Stateless API 요청 처리 등에 유용합니다:
if (Auth::once($credentials)) {
// ...
}HTTP Basic 인증
HTTP Basic 인증은 별도의 로그인 페이지 없이 빠르게 인증을 구성하는 방법입니다. 라우트에 auth.basic 미들웨어를 추가하면 됩니다. 이 미들웨어는 Laravel에 기본 포함되어 있습니다:
Route::get('/profile', function () {
// 인증된 사용자만 접근 가능합니다.
})->middleware('auth.basic');미들웨어가 라우트에 적용되면 브라우저에서 해당 URL에 접근할 때 자동으로 인증 자격 증명 입력 창이 표시됩니다. 기본적으로 auth.basic 미들웨어는 users 테이블의 email 컬럼을 사용자명으로 사용합니다.
FastCGI 관련 주의사항
PHP FastCGI와 Apache를 함께 사용하는 경우, HTTP Basic 인증이 정상적으로 동작하지 않을 수 있습니다. 이 경우 .htaccess 파일에 다음 내용을 추가하세요:
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]Stateless HTTP Basic 인증
세션에 사용자 식별 쿠키를 저장하지 않고 HTTP Basic 인증을 사용할 수도 있습니다. 주로 API 인증에 활용됩니다. 이를 위해 onceBasic() 메서드를 호출하는 미들웨어를 정의하세요. onceBasic()이 응답을 반환하지 않으면 요청이 애플리케이션 내부로 계속 전달됩니다:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class AuthenticateOnceWithBasicAuth
{
/**
* 들어오는 요청을 처리합니다.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
return Auth::onceBasic() ?: $next($request);
}
}그리고 라우트에 이 미들웨어를 적용합니다:
Route::get('/api/user', function () {
// 인증된 사용자만 접근 가능합니다.
})->middleware(AuthenticateOnceWithBasicAuth::class);로그아웃
애플리케이션에서 사용자를 로그아웃하려면 Auth 파사드의 logout() 메서드를 사용합니다. 이 메서드는 세션에서 인증 정보를 제거합니다.
logout() 호출 후에는 세션을 무효화하고, 새로운 CSRF 토큰을 생성하는 것이 좋습니다. 로그아웃 처리가 끝나면 보통 애플리케이션의 루트로 리디렉션합니다:
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
/**
* 사용자를 애플리케이션에서 로그아웃합니다.
*/
public function logout(Request $request): RedirectResponse
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}다른 기기의 세션 무효화
Laravel은 현재 기기의 세션은 유지하면서, 다른 기기에서 활성화된 세션만 무효화하는 기능도 제공합니다. 비밀번호 변경 시 다른 기기에서 강제 로그아웃하는 용도로 유용합니다.
이 기능을 사용하려면 먼저 Illuminate\Session\Middleware\AuthenticateSession 미들웨어가 해당 라우트에 적용되어 있어야 합니다. 보통 라우트 그룹에 적용해 많은 라우트에 한꺼번에 사용합니다. bootstrap/app.php에서 auth.session 미들웨어 별칭으로 설정할 수 있습니다:
use Illuminate\Session\Middleware\AuthenticateSession;
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'auth.session' => AuthenticateSession::class,
]);
})그 다음, 라우트에 적용합니다:
Route::middleware(['auth', 'auth.session'])->group(function () {
Route::get('/', function () {
// ...
});
});그 후 Auth 파사드의 logoutOtherDevices() 메서드를 호출합니다. 이 메서드는 현재 비밀번호를 인수로 받아 확인합니다:
use Illuminate\Support\Facades\Auth;
Auth::logoutOtherDevices($currentPassword);이 메서드를 호출하면 다른 기기의 세션이 완전히 무효화되어, 모든 가드에서 로그아웃됩니다.
비밀번호 확인
특정 작업을 수행하기 전에 사용자에게 비밀번호를 다시 입력하도록 요구해야 하는 경우가 있습니다. Laravel은 이를 위한 password.confirm 미들웨어를 기본으로 제공합니다.
설정
비밀번호 확인 후 사용자는 기본적으로 3시간 동안 다시 확인 없이 해당 영역을 이용할 수 있습니다. 이 시간은 config/auth.php의 password_timeout 값으로 조정할 수 있습니다.
라우팅
비밀번호 확인 기능을 사용하려면 두 가지 라우트가 필요합니다.
첫 번째는 비밀번호 입력 폼을 사용자에게 보여주는 라우트입니다:
Route::get('/confirm-password', function () {
return view('auth.confirm-password');
})->middleware('auth')->name('password.confirm');두 번째는 폼 제출을 처리하는 라우트입니다. 비밀번호 유효성을 검사하고 사용자를 원래 목적지로 리디렉션합니다:
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redirect;
Route::post('/confirm-password', function (Request $request): RedirectResponse {
if (! Hash::check($request->password, $request->user()->password)) {
return back()->withErrors([
'password' => '입력하신 비밀번호가 올바르지 않습니다.',
]);
}
$request->session()->passwordConfirmed();
return redirect()->intended();
})->middleware(['auth', 'throttle:6,1']);위 코드를 살펴보면, Hash::check()로 비밀번호를 검증한 후, session()->passwordConfirmed()를 호출하여 세션에 비밀번호 확인 시각을 기록합니다. 이후 미들웨어가 이를 확인해 재입력 여부를 결정합니다.
라우트 보호
비밀번호를 최근에 확인한 사용자만 접근할 수 있는 라우트에는 password.confirm 미들웨어를 적용하세요:
Route::get('/settings', function () {
// ...
})->middleware(['auth', 'password.confirm']);처음 이 라우트에 접근하면 비밀번호 확인 화면으로 리디렉션됩니다. 확인이 완료되면 원래 목적지로 자동으로 이동됩니다.
커스텀 가드 추가
Auth 파사드의 extend() 메서드를 사용하면 커스텀 인증 가드를 정의할 수 있습니다. 이 코드는 서비스 프로바이더 안에 위치시켜야 합니다. Laravel에는 이미 AppServiceProvider가 있으니, 거기에 추가해도 됩니다:
<?php
namespace App\Providers;
use App\Services\Auth\JwtGuard;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* 모든 애플리케이션 서비스를 부트스트랩합니다.
*/
public function boot(): void
{
Auth::extend('jwt', function (Application $app, string $name, array $config) {
// Illuminate\Contracts\Auth\Guard 구현체를 반환합니다.
return new JwtGuard(Auth::createUserProvider($config['provider']));
});
}
}위 예시처럼 extend()에 전달한 클로저는 Illuminate\Contracts\Auth\Guard 구현체를 반환해야 합니다. 이 인터페이스에 정의된 메서드를 모두 구현해야 합니다.
커스텀 가드를 정의했다면, config/auth.php의 guards 설정에서 사용합니다:
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],클로저 요청 가드
HTTP 요청 기반의 커스텀 인증 시스템을 간단하게 구현하려면 Auth::viaRequest() 메서드를 사용하세요. 별도의 가드 클래스 없이 클로저 하나로 인증 로직을 정의할 수 있습니다.
AppServiceProvider의 boot() 메서드 안에서 Auth::viaRequest()를 호출합니다. 첫 번째 인수는 가드 이름(임의의 문자열), 두 번째 인수는 요청을 받아 인증된 사용자 인스턴스를 반환하거나, 인증 실패 시 null을 반환하는 클로저입니다:
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
/**
* 모든 애플리케이션 서비스를 부트스트랩합니다.
*/
public function boot(): void
{
Auth::viaRequest('custom-token', function (Request $request) {
return User::where('token', (string) $request->token)->first();
});
}클로저 요청 가드를 정의했다면, config/auth.php의 guards 설정에서 사용합니다:
'guards' => [
'api' => [
'driver' => 'custom-token',
],
],마지막으로 라우트에 인증 미들웨어를 적용할 때 해당 가드를 지정합니다:
Route::middleware('auth:api')->group(function () {
// ...
});커스텀 사용자 프로바이더 추가
관계형 데이터베이스 외의 저장소(예: MongoDB, Redis, 외부 API)에서 사용자를 조회해야 한다면 커스텀 사용자 프로바이더를 구현할 수 있습니다.
Auth 파사드의 provider() 메서드로 커스텀 프로바이더를 등록합니다. 서비스 프로바이더에서 등록하는 것이 좋습니다:
<?php
namespace App\Providers;
use App\Extensions\MongoUserProvider;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* 모든 애플리케이션 서비스를 부트스트랩합니다.
*/
public function boot(): void
{
Auth::provider('mongo', function (Application $app, array $config) {
// Illuminate\Contracts\Auth\UserProvider 구현체를 반환합니다.
return new MongoUserProvider($app->make('mongo.connection'));
});
}
}프로바이더를 등록했다면, config/auth.php에서 사용합니다:
'providers' => [
'users' => [
'driver' => 'mongo',
],
],그리고 이 프로바이더를 원하는 가드의 provider 항목에 지정합니다:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],User Provider 컨트랙트
Illuminate\Contracts\Auth\UserProvider 구현체는 MySQL, MongoDB 등 영속 저장소에서 Illuminate\Contracts\Auth\Authenticatable 구현체를 가져오는 역할을 합니다. 이 두 인터페이스 덕분에 사용자 데이터를 어디에 저장하든, 어떤 클래스로 표현하든 Laravel의 인증 시스템이 동작할 수 있습니다:
<?php
namespace Illuminate\Contracts\Auth;
interface UserProvider
{
public function retrieveById($identifier);
public function retrieveByToken($identifier, $token);
public function updateRememberToken(Authenticatable $user, $token);
public function retrieveByCredentials(array $credentials);
public function validateCredentials(Authenticatable $user, array $credentials);
public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false);
}각 메서드의 역할을 간략히 설명합니다:
retrieveById: 사용자 ID(보통 DB의 primary key)로 사용자를 조회합니다.retrieveByToken: 고유 식별자와remember_token값으로 사용자를 조회합니다.updateRememberToken: 사용자의remember_token을 새 토큰으로 업데이트합니다. "로그인 상태 유지" 인증 성공 시 또는 로그아웃 시 호출됩니다.retrieveByCredentials:Auth::attempt()호출 시 전달된 자격 증명 배열을 받아 사용자를 조회합니다. 비밀번호 검증은 이 메서드에서 하지 않습니다.validateCredentials: 사용자 인스턴스와 자격 증명을 비교해 인증 여부를 반환합니다. 보통Hash::check()를 사용해 비밀번호를 검증합니다.rehashPasswordIfRequired: 필요한 경우 사용자의 비밀번호를 재해싱합니다. 자세한 내용은 자동 비밀번호 재해싱 섹션을 참고하세요.
Authenticatable 컨트랙트
UserProvider의 각 메서드를 살펴봤으니, 이번에는 Authenticatable 컨트랙트를 알아봅니다. 프로바이더의 retrieveById, retrieveByToken, retrieveByCredentials 메서드는 이 인터페이스 구현체를 반환해야 합니다:
<?php
namespace Illuminate\Contracts\Auth;
interface Authenticatable
{
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPasswordName();
public function getAuthPassword();
public function getRememberToken();
public function setRememberToken($value);
public function getRememberTokenName();
}각 메서드의 역할은 간단합니다:
getAuthIdentifierName: 사용자의 "primary key" 컬럼명을 반환합니다.getAuthIdentifier: 사용자의 primary key 값을 반환합니다.getAuthPasswordName: 비밀번호 컬럼명을 반환합니다.getAuthPassword: 해시된 비밀번호를 반환합니다.getRememberToken/setRememberToken/getRememberTokenName: "로그인 상태 유지" 기능에 사용하는 토큰 관련 메서드입니다.
이 인터페이스를 구현하면 어떤 ORM이나 데이터 클래스든 인증 시스템에서 사용할 수 있습니다. Laravel은 기본으로 app/Models/User.php에 이 인터페이스를 구현한 User 모델을 제공합니다.
자동 비밀번호 재해싱
Laravel의 기본 비밀번호 해싱 알고리즘은 bcrypt입니다. bcrypt의 "work factor"(해싱 강도)는 config/hashing.php 또는 BCRYPT_ROUNDS 환경 변수로 조정할 수 있습니다.
일반적으로 하드웨어 성능이 향상됨에 따라 bcrypt work factor를 점차 높여야 합니다. work factor를 높이면, 사용자가 로그인할 때 Laravel이 자동으로 비밀번호를 새로운 강도로 재해싱합니다. 이 자동 재해싱은 attempt(), login(), loginUsingId() 메서드 사용 시 자동으로 처리됩니다.
NOTE
자동 재해싱은 보통 백그라운드에서 조용히 처리됩니다. 하지만 비밀번호 재해싱 이벤트에 맞춰 별도 처리(예: 알림 발송)가 필요하다면 비밀번호 재해싱 이벤트를 리스닝할 수 있습니다.
일부 경우에는 로그인 중에 자동 재해싱을 비활성화하고 싶을 수 있습니다. 예를 들어 API 인증처럼 비밀번호를 재해싱해도 응답에 직접 영향을 주지 않는 환경에서는 성능 최적화를 위해 비활성화할 수 있습니다. attempt() 메서드에 rehash: false 인수를 전달하면 됩니다:
Auth::attempt($credentials, rehash: false);이벤트
Laravel은 인증 처리 과정에서 다양한 이벤트를 발생시킵니다. 다음 이벤트들에 리스너를 등록할 수 있습니다:
| 이벤트 이름 |
|---|
Illuminate\Auth\Events\Registered |
Illuminate\Auth\Events\Attempting |
Illuminate\Auth\Events\Authenticated |
Illuminate\Auth\Events\Login |
Illuminate\Auth\Events\Failed |
Illuminate\Auth\Events\Validated |
Illuminate\Auth\Events\Verified |
Illuminate\Auth\Events\Logout |
Illuminate\Auth\Events\CurrentDeviceLogout |
Illuminate\Auth\Events\OtherDeviceLogout |
Illuminate\Auth\Events\Lockout |
Illuminate\Auth\Events\PasswordReset |
Illuminate\Auth\Events\PasswordResetLinkSent |
인증
목차
소개
대부분의 웹 애플리케이션은 사용자가 로그인할 수 있는 인증 기능을 제공합니다. 이 기능을 직접 구현하는 것은 생각보다 복잡하고, 잘못 구현하면 보안 취약점이 생기기 쉽습니다. Laravel은 이러한 인증 기능을 빠르고 안전하게 구현할 수 있는 도구를 기본으로 제공합니다.
Laravel 인증의 핵심 개념은 가드(guard) 와 프로바이더(provider) 입니다.
- 가드: 각 요청에서 사용자를 어떻게 인증할지 정의합니다. 예를 들어 기본으로 제공되는
session가드는 세션 스토리지와 쿠키를 사용해 인증 상태를 유지합니다. - 프로바이더: 영속적인 저장소(데이터베이스 등)에서 사용자 정보를 어떻게 가져올지 정의합니다. 기본적으로 Eloquent와 쿼리 빌더를 지원하며, 필요에 따라 커스텀 프로바이더를 추가할 수도 있습니다.
인증 관련 설정은 config/auth.php 파일에서 관리합니다. 각 옵션에 대한 설명이 잘 정리되어 있으므로 참고해 보세요.
NOTE
가드와 프로바이더는 "역할(role)"이나 "권한(permission)"과는 다른 개념입니다. 사용자 행동에 대한 권한 부여는 인가(authorization) 문서를 참고하세요.
스타터 킷
빠르게 시작하고 싶다면, 새 Laravel 프로젝트에 애플리케이션 스타터 킷을 설치하세요. 데이터베이스 마이그레이션 후 브라우저에서 /register 또는 앱에 지정된 다른 URL에 접속하면 됩니다. 스타터 킷이 인증 시스템 전체를 자동으로 구성해 줍니다.
최종 프로젝트에서 스타터 킷을 사용하지 않더라도, Laravel Breeze를 먼저 설치해 보는 것을 강력히 권장합니다. Breeze는 인증 컨트롤러, 라우트, 뷰를 자동으로 생성해 주기 때문에, 생성된 코드를 살펴보는 것만으로도 Laravel 인증 기능이 실제로 어떻게 동작하는지 빠르게 파악할 수 있습니다.
데이터베이스 고려사항
Laravel은 기본적으로 app/Models 디렉터리에 App\Models\User Eloquent 모델을 포함하고 있습니다. 이 모델은 기본 Eloquent 인증 드라이버와 함께 사용됩니다.
Eloquent를 사용하지 않는다면 Laravel 쿼리 빌더 기반의 database 인증 프로바이더를 사용할 수 있습니다. MongoDB를 사용하는 경우에는 MongoDB 공식 Laravel 사용자 인증 문서를 참고하세요.
App\Models\User 모델의 데이터베이스 스키마를 설계할 때는 다음 두 가지를 반드시 확인하세요.
password컬럼은 최소 60자 이상이어야 합니다.remember_token컬럼은 nullable한 100자 문자열이어야 합니다. 이 컬럼은 사용자가 "로그인 상태 유지"를 선택했을 때 토큰을 저장하는 데 사용됩니다.
새 Laravel 프로젝트에 기본으로 포함된 users 테이블 마이그레이션은 이 두 조건을 모두 충족하므로, 기본 마이그레이션을 그대로 사용하면 별도의 수정이 필요 없습니다.
생태계 개요
Laravel은 인증과 관련된 여러 패키지를 제공합니다. 각 패키지의 역할을 이해하면 프로젝트에 맞는 선택을 하기가 훨씬 쉬워집니다. 먼저 인증이 어떻게 동작하는지 살펴보겠습니다.
브라우저 기반 인증의 흐름:
웹 브라우저를 사용하는 경우, 사용자는 로그인 폼에 아이디와 비밀번호를 입력합니다. 자격증명이 올바르면 애플리케이션은 인증된 사용자 정보를 세션에 저장하고, 브라우저에 세션 ID가 담긴 쿠키를 발급합니다. 이후 요청에서는 이 쿠키를 통해 사용자를 식별합니다.
API 기반 인증의 흐름:
API를 통해 외부 서비스가 인증하는 경우에는 쿠키 대신 API 토큰을 사용합니다. 외부 서비스는 매 요청마다 API 토큰을 함께 전송하고, 애플리케이션은 이 토큰을 검증해 요청을 인증합니다.
Laravel 내장 브라우저 인증 서비스
Laravel은 Auth와 Session 파사드를 통해 접근할 수 있는 인증 및 세션 서비스를 내장하고 있습니다. 이 서비스들은 웹 브라우저로부터의 요청에 대한 쿠키 기반 인증을 담당하며, 자격증명 검증, 사용자 인증, 세션 데이터 저장, 세션 쿠키 발급 등을 처리합니다.
애플리케이션 스타터 킷
인증 서비스를 직접 구현할 수도 있지만, 더 빠르게 시작할 수 있도록 Laravel은 인증 레이어 전체를 포함하는 무료 패키지를 제공합니다.
-
Laravel Breeze: 로그인, 회원가입, 비밀번호 재설정, 이메일 인증, 비밀번호 확인 등 Laravel 인증 기능의 간결한 구현체입니다. Blade 템플릿과 Tailwind CSS로 구성되어 있으며, 인증을 처음 공부하는 분께 가장 적합합니다.
-
Laravel Fortify: UI가 없는 헤드리스 인증 백엔드입니다. 쿠키 기반 인증 외에도 2단계 인증, 이메일 인증 등의 기능을 제공합니다. Laravel Jetstream의 인증 백엔드로 사용되거나, Laravel Sanctum과 함께 SPA 인증에 활용됩니다.
-
Laravel Jetstream: Fortify를 기반으로 하며, Tailwind CSS, Livewire, Inertia로 구성된 현대적인 UI를 제공합니다. 2단계 인증, 팀 관리, 브라우저 세션 관리, 프로필 관리, Laravel Sanctum 연동을 통한 API 토큰 인증 등 풍부한 기능을 갖추고 있습니다.
Laravel API 인증 서비스
API 토큰 인증을 위한 두 가지 패키지를 제공합니다. 이 패키지들은 내장 쿠키 기반 인증과 함께 사용할 수 있으며, 서로 배타적이지 않습니다.
Passport
Passport는 OAuth2 인증 프로바이더로, 다양한 OAuth2 "그랜트 타입"을 통해 여러 종류의 토큰을 발급할 수 있습니다. 강력하지만 복잡한 패키지로, OAuth2 명세의 모든 기능이 필요한 경우에 적합합니다. 다만 대부분의 애플리케이션에서는 OAuth2의 복잡한 기능이 모두 필요하지 않으며, SPA나 모바일 앱에서 OAuth2를 활용하는 방법이 혼란스럽게 느껴질 수 있습니다.
Sanctum
OAuth2의 복잡함을 해결하기 위해 만들어진 패키지입니다. 브라우저의 웹 요청과 API 토큰 요청을 모두 처리할 수 있는 하이브리드 인증 패키지입니다.
Sanctum 기반 애플리케이션이 요청을 받으면 다음과 같이 동작합니다.
자체 웹 UI와 API를 함께 제공하거나, 별도의 SPA 프런트엔드가 Laravel 백엔드와 통신하거나, 모바일 클라이언트를 지원하는 애플리케이션이라면 Sanctum을 우선적으로 고려하세요. Sanctum은 Laravel Jetstream의 기본 API 인증 패키지로 채택될 만큼 범용성이 높습니다.
Sanctum의 동작 방식에 대한 자세한 내용은 Sanctum 문서의 "동작 원리" 섹션을 참고하세요.
요약 및 스택 선택 가이드
프로젝트 유형에 따라 아래 기준으로 선택하면 됩니다.
| 상황 | 권장 선택 |
|---|---|
| 브라우저 기반 모놀리식 Laravel 앱 | Laravel 내장 인증 서비스 |
| 서드파티가 소비하는 API 제공 (대부분의 경우) | Sanctum |
| Laravel 백엔드를 사용하는 SPA | Sanctum |
| 모바일 클라이언트 지원 | Sanctum |
| OAuth2 명세의 모든 기능이 필요한 경우 | Passport |
빠르게 시작하고 싶다면 Laravel Breeze를 추천합니다. Breeze는 Laravel 내장 인증 서비스와 Sanctum을 함께 사용하는 선호 인증 스택으로 새 프로젝트를 바로 시작할 수 있게 해줍니다.
인증 퀵스타트
WARNING
이 섹션은 Laravel 애플리케이션 스타터 킷을 통해 사용자를 인증하는 방법을 다룹니다. 스타터 킷은 UI 스캐폴딩을 포함하고 있어 빠르게 시작할 수 있습니다. Laravel의 인증 시스템을 직접 통합하고 싶다면 수동으로 사용자 인증하기 문서를 참고하세요.
스타터 킷 설치
먼저 Laravel 애플리케이션 스타터 킷을 설치합니다. 현재 제공되는 스타터 킷은 Laravel Breeze와 Laravel Jetstream 두 가지이며, 새 Laravel 애플리케이션에 인증 기능을 손쉽게 추가할 수 있도록 잘 설계된 시작점을 제공합니다.
Laravel Breeze는 로그인, 회원가입, 비밀번호 재설정, 이메일 인증, 비밀번호 확인 등 Laravel의 모든 인증 기능을 간결하게 구현한 패키지입니다. 뷰 레이어는 Tailwind CSS로 스타일링된 단순한 Blade 템플릿으로 구성됩니다. 또한 Livewire나 Inertia 기반 스캐폴딩도 선택할 수 있으며, Inertia를 사용할 경우 Vue 또는 React 중 원하는 프론트엔드 스택을 고를 수 있습니다.
**Laravel Jetstream**은 보다 풍부한 기능을 갖춘 스타터 킷으로, Livewire 또는 Inertia + Vue 스캐폴딩을 지원합니다. 이 외에도 2단계 인증(2FA), 팀 관리, 프로필 관리, 브라우저 세션 관리, Laravel Sanctum을 통한 API 지원, 계정 삭제 등 다양한 기능을 선택적으로 활용할 수 있습니다.
인증된 사용자 가져오기
스타터 킷을 설치하고 사용자가 회원가입 및 로그인을 할 수 있게 되면, 현재 인증된 사용자 정보를 가져와야 하는 경우가 자주 생깁니다. 요청을 처리하는 도중에는 Auth 파사드의 user 메서드를 통해 인증된 사용자에 접근할 수 있습니다.
use Illuminate\Support\Facades\Auth;
// 현재 인증된 사용자 가져오기
$user = Auth::user();
// 현재 인증된 사용자의 ID 가져오기
$id = Auth::id();또는, 컨트롤러 메서드에서 Illuminate\Http\Request 인스턴스를 타입힌트로 주입받아 user() 메서드로 인증된 사용자에 접근할 수도 있습니다. 타입힌트된 클래스는 컨트롤러 메서드에 자동으로 주입되므로, 애플리케이션 내 어느 컨트롤러에서든 편리하게 사용할 수 있습니다.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class FlightController extends Controller
{
/**
* 항공편 정보를 업데이트합니다.
*/
public function update(Request $request): RedirectResponse
{
$user = $request->user();
// ...
return redirect('/flights');
}
}현재 사용자가 인증되어 있는지 확인하기
현재 HTTP 요청을 보낸 사용자가 인증되어 있는지 확인하려면 Auth 파사드의 check 메서드를 사용합니다. 인증된 사용자라면 true를 반환합니다.
use Illuminate\Support\Facades\Auth;
if (Auth::check()) {
// 사용자가 로그인한 상태입니다.
}NOTE
check 메서드로 인증 여부를 확인할 수 있지만, 실제로는 특정 라우트나 컨트롤러에 접근하기 전에 미들웨어로 인증을 검증하는 방식이 일반적입니다. 자세한 내용은 라우트 보호하기 문서를 참고하세요.
라우트 보호하기
라우트 미들웨어를 사용하면 인증된 사용자만 특정 라우트에 접근하도록 제한할 수 있습니다. Laravel은 Illuminate\Auth\Middleware\Authenticate 클래스의 미들웨어 별칭인 auth 미들웨어를 기본으로 제공합니다. 이미 내부적으로 별칭이 등록되어 있으므로, 라우트 정의에 간단히 붙여주기만 하면 됩니다.
Route::get('/flights', function () {
// 인증된 사용자만 접근 가능합니다.
})->middleware('auth');비인증 사용자 리디렉션
auth 미들웨어가 인증되지 않은 사용자를 감지하면, 해당 사용자를 login이라는 이름이 지정된 라우트로 리디렉션합니다. 이 동작은 bootstrap/app.php 파일의 redirectGuestsTo 메서드를 통해 변경할 수 있습니다.
use Illuminate\Http\Request;
->withMiddleware(function (Middleware $middleware) {
$middleware->redirectGuestsTo('/login');
// 클로저를 사용하는 방법
$middleware->redirectGuestsTo(fn (Request $request) => route('login'));
})가드 지정하기
auth 미들웨어를 라우트에 적용할 때, 사용자 인증에 사용할 "가드"를 함께 지정할 수 있습니다. 지정하는 가드 이름은 auth.php 설정 파일의 guards 배열에 정의된 키 중 하나여야 합니다.
Route::get('/flights', function () {
// 인증된 사용자만 접근 가능합니다.
})->middleware('auth:admin');로그인 시도 제한
Laravel Breeze 또는 Laravel Jetstream 스타터 킷을 사용하는 경우, 로그인 시도에 자동으로 횟수 제한(Rate Limiting)이 적용됩니다. 기본 설정에서는 사용자가 여러 번 잘못된 자격증명을 입력하면 1분 동안 로그인이 차단됩니다. 이 제한은 사용자의 아이디(이메일 포함)와 IP 주소 조합을 기준으로 적용됩니다.
NOTE
애플리케이션의 다른 라우트에도 요청 횟수 제한을 적용하고 싶다면 속도 제한 문서를 참고하세요.
인증
직접 사용자 인증 처리하기
Laravel의 애플리케이션 스타터 킷이 제공하는 인증 스캐폴딩을 반드시 사용할 필요는 없습니다. 스타터 킷을 사용하지 않는다면, Laravel 인증 클래스를 직접 다루어 사용자 인증을 구현해야 합니다. 어렵지 않으니 걱정하지 마세요.
Auth 파사드를 통해 Laravel의 인증 서비스에 접근할 수 있습니다. 클래스 상단에 Auth 파사드를 임포트하는 것을 잊지 마세요. 이제 attempt 메서드를 살펴보겠습니다. attempt 메서드는 보통 애플리케이션의 "로그인" 폼에서 인증 시도를 처리할 때 사용합니다. 인증에 성공하면 세션 고정 공격을 방지하기 위해 반드시 사용자의 세션을 재생성해야 합니다.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
/**
* 인증 시도를 처리합니다.
*/
public function authenticate(Request $request): RedirectResponse
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
return redirect()->intended('dashboard');
}
return back()->withErrors([
'email' => '입력하신 정보와 일치하는 계정을 찾을 수 없습니다.',
])->onlyInput('email');
}
}attempt 메서드는 첫 번째 인수로 키/값 쌍의 배열을 받습니다. 배열의 값들은 데이터베이스에서 사용자를 조회하는 데 사용됩니다. 위 예시에서는 email 컬럼 값으로 사용자를 찾습니다. 사용자가 존재하면, 데이터베이스에 저장된 해시된 비밀번호와 배열에 전달된 password 값을 비교합니다. 요청으로 들어온 password 값을 직접 해싱하지 않아도 됩니다. 프레임워크가 비교 전에 자동으로 해싱 처리를 하기 때문입니다. 두 비밀번호가 일치하면 해당 사용자에 대한 인증 세션이 시작됩니다.
Laravel의 인증 서비스는 config/auth.php의 인증 가드 "provider" 설정을 기반으로 데이터베이스에서 사용자를 조회합니다. 기본 설정에서는 Eloquent 사용자 프로바이더가 지정되어 있으며, App\Models\User 모델을 사용하도록 되어 있습니다. 애플리케이션의 요구에 따라 설정 파일에서 이 값들을 변경할 수 있습니다.
attempt 메서드는 인증에 성공하면 true를, 실패하면 false를 반환합니다.
intended 메서드는 인증 미들웨어에 의해 차단되기 전에 사용자가 접근하려 했던 URL로 리다이렉트합니다. 원래 목적지를 알 수 없는 경우를 대비해 대체 URI를 인수로 전달할 수 있습니다.
추가 조건 지정하기
이메일과 비밀번호 외에 추가 쿼리 조건을 인증 쿼리에 포함할 수도 있습니다. attempt 메서드에 전달하는 배열에 조건을 추가하면 됩니다. 예를 들어, 사용자가 "활성" 상태인지 확인하려면 다음과 같이 작성합니다.
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// 인증 성공...
}복잡한 쿼리 조건이 필요한 경우, 배열에 클로저를 포함할 수 있습니다. 이 클로저는 쿼리 인스턴스를 받으므로, 애플리케이션의 필요에 맞게 쿼리를 자유롭게 커스터마이즈할 수 있습니다.
use Illuminate\Database\Eloquent\Builder;
if (Auth::attempt([
'email' => $email,
'password' => $password,
fn (Builder $query) => $query->has('activeSubscription'),
])) {
// 인증 성공...
}WARNING
위 예시에서 email은 필수 항목이 아니라 단순한 예시입니다. 실제 데이터베이스 테이블에서 "사용자명" 역할을 하는 컬럼명을 사용하세요.
attemptWhen 메서드는 두 번째 인수로 클로저를 받으며, 실제 인증을 진행하기 전에 사용자를 더 세밀하게 검사할 때 사용합니다. 클로저는 잠재적 사용자 인스턴스를 받고, 인증 허용 여부에 따라 true 또는 false를 반환해야 합니다.
if (Auth::attemptWhen([
'email' => $email,
'password' => $password,
], function (User $user) {
return $user->isNotBanned();
})) {
// 인증 성공...
}특정 가드 인스턴스 사용하기
Auth 파사드의 guard 메서드를 사용하면 인증 시 사용할 가드 인스턴스를 지정할 수 있습니다. 이를 통해 애플리케이션의 서로 다른 영역(예: 일반 사용자와 관리자)을 별도의 인증 가능한 모델이나 사용자 테이블로 분리해서 관리할 수 있습니다.
guard 메서드에 전달하는 가드 이름은 auth.php 설정 파일에 정의된 가드 중 하나여야 합니다.
if (Auth::guard('admin')->attempt($credentials)) {
// ...
}로그인 상태 유지 (Remember Me)
많은 웹 애플리케이션의 로그인 폼에는 "로그인 상태 유지" 체크박스가 있습니다. 이 기능을 제공하려면 attempt 메서드의 두 번째 인수로 불리언 값을 전달하면 됩니다.
이 값이 true이면, Laravel은 사용자가 직접 로그아웃하기 전까지 인증 상태를 무기한 유지합니다. 이 기능을 사용하려면 users 테이블에 "remember me" 토큰을 저장할 remember_token 문자열 컬럼이 있어야 합니다. 새 Laravel 애플리케이션에 포함된 users 테이블 마이그레이션에는 이 컬럼이 이미 포함되어 있습니다.
use Illuminate\Support\Facades\Auth;
if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {
// 로그인 상태 유지 중...
}"로그인 상태 유지" 기능을 제공하는 경우, viaRemember 메서드를 사용하여 현재 인증된 사용자가 "remember me" 쿠키를 통해 인증되었는지 확인할 수 있습니다.
use Illuminate\Support\Facades\Auth;
if (Auth::viaRemember()) {
// ...
}그 밖의 인증 방법
사용자 인스턴스로 인증하기
기존 사용자 인스턴스를 현재 인증된 사용자로 지정해야 하는 경우, Auth 파사드의 login 메서드에 해당 인스턴스를 전달하면 됩니다. 전달하는 사용자 인스턴스는 Illuminate\Contracts\Auth\Authenticatable 컨트랙트를 구현해야 합니다. Laravel에 포함된 App\Models\User 모델은 이미 이 인터페이스를 구현하고 있습니다. 이 방법은 회원 가입 직후처럼 유효한 사용자 인스턴스를 이미 보유하고 있을 때 유용합니다.
use Illuminate\Support\Facades\Auth;
Auth::login($user);login 메서드의 두 번째 인수로 불리언 값을 전달하여 "로그인 상태 유지" 여부를 지정할 수 있습니다. true로 설정하면 사용자가 직접 로그아웃하기 전까지 인증 세션이 무기한 유지됩니다.
Auth::login($user, $remember = true);필요한 경우 login 메서드를 호출하기 전에 인증 가드를 지정할 수 있습니다.
Auth::guard('admin')->login($user);ID로 사용자 인증하기
데이터베이스 레코드의 기본 키를 사용하여 사용자를 인증하려면 loginUsingId 메서드를 사용하세요. 인증할 사용자의 기본 키를 인수로 전달합니다.
Auth::loginUsingId(1);loginUsingId 메서드의 remember 인수에 불리언 값을 전달하여 "로그인 상태 유지" 여부를 지정할 수 있습니다. true로 설정하면 사용자가 직접 로그아웃하기 전까지 인증 세션이 무기한 유지됩니다.
Auth::loginUsingId(1, remember: true);단일 요청에만 인증하기
once 메서드를 사용하면 단 하나의 요청에 대해서만 사용자를 인증할 수 있습니다. 이 메서드를 호출할 때는 세션이나 쿠키를 사용하지 않습니다. API처럼 상태를 유지하지 않는 환경에서 유용합니다.
if (Auth::once($credentials)) {
// ...
}HTTP Basic 인증
HTTP Basic 인증은 별도의 로그인 페이지 없이 사용자를 빠르게 인증할 수 있는 방법입니다. 라우트에 auth.basic 미들웨어를 붙이는 것만으로 동작합니다. auth.basic 미들웨어는 Laravel 프레임워크에 이미 포함되어 있으므로 별도로 정의할 필요가 없습니다.
Route::get('/profile', function () {
// 인증된 사용자만 접근할 수 있습니다...
})->middleware('auth.basic');미들웨어를 라우트에 적용하면, 브라우저에서 해당 경로에 접근할 때 자동으로 자격 증명 입력 창이 나타납니다. 기본적으로 auth.basic 미들웨어는 users 테이블의 email 컬럼을 사용자 아이디(username)로 사용합니다.
FastCGI 사용 시 주의사항
PHP FastCGI와 Apache 조합으로 Laravel 애플리케이션을 서빙하는 경우, HTTP Basic 인증이 제대로 동작하지 않을 수 있습니다. 이 경우 애플리케이션의 .htaccess 파일에 다음 내용을 추가하면 해결됩니다.
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]상태 비저장(Stateless) HTTP Basic 인증
세션에 사용자 식별 쿠키를 저장하지 않고 HTTP Basic 인증을 사용할 수도 있습니다. 이 방식은 API 요청을 인증할 때 특히 유용합니다. 구현하려면 onceBasic 메서드를 호출하는 미들웨어를 정의하면 됩니다. onceBasic이 응답을 반환하지 않으면 요청이 애플리케이션 내부로 계속 전달됩니다.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class AuthenticateOnceWithBasicAuth
{
/**
* 들어오는 요청을 처리합니다.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
return Auth::onceBasic() ?: $next($request);
}
}이후 해당 미들웨어를 라우트에 적용합니다.
Route::get('/api/user', function () {
// 인증된 사용자만 접근할 수 있습니다...
})->middleware(AuthenticateOnceWithBasicAuth::class);NOTE
onceBasic은 세션에 인증 상태를 기록하지 않습니다. 즉, 매 요청마다 자격 증명을 확인합니다. API처럼 세션을 사용하지 않는 환경에 적합하며, 일반 웹 페이지에는 적합하지 않습니다.
로그아웃
사용자를 수동으로 로그아웃시키려면 Auth 파사드의 logout 메서드를 사용합니다. 이 메서드를 호출하면 세션에서 인증 정보가 제거되어, 이후 요청은 인증되지 않은 상태로 처리됩니다.
logout 메서드 호출과 함께, 세션을 무효화하고 CSRF 토큰을 재생성하는 것도 권장합니다. 로그아웃 후에는 일반적으로 사용자를 애플리케이션의 루트 경로로 리디렉션합니다.
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
/**
* 사용자를 로그아웃 처리합니다.
*/
public function logout(Request $request): RedirectResponse
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}NOTE
세션 무효화(invalidate)와 토큰 재생성(regenerateToken)을 함께 처리하지 않으면, 로그아웃 후에도 이전 세션이나 CSRF 토큰이 재사용될 수 있습니다. 보안을 위해 세 단계를 항상 함께 수행하세요.
다른 기기의 세션 무효화
Laravel은 현재 기기의 세션은 유지하면서 다른 기기에서 활성화된 세션만 무효화하는 기능도 제공합니다. 이 기능은 주로 사용자가 비밀번호를 변경할 때, 현재 로그인 상태는 유지하되 다른 기기에서의 로그인을 모두 강제 종료하고 싶을 때 활용합니다.
먼저, 세션 인증이 필요한 라우트에 Illuminate\Session\Middleware\AuthenticateSession 미들웨어가 적용되어 있는지 확인해야 합니다. 보통은 라우트 그룹에 이 미들웨어를 지정하여 애플리케이션의 대부분의 라우트에 일괄 적용합니다. 기본적으로 auth.session이라는 미들웨어 별칭으로 사용할 수 있습니다.
Route::middleware(['auth', 'auth.session'])->group(function () {
Route::get('/', function () {
// ...
});
});미들웨어를 적용한 후, Auth 파사드의 logoutOtherDevices 메서드를 호출합니다. 이 메서드는 사용자의 현재 비밀번호를 요구하므로, 애플리케이션에서 입력 폼을 통해 비밀번호를 받아야 합니다.
use Illuminate\Support\Facades\Auth;
Auth::logoutOtherDevices($currentPassword);logoutOtherDevices 메서드가 실행되면, 해당 사용자의 다른 모든 세션이 완전히 무효화됩니다. 즉, 이전에 인증되었던 모든 가드에서 로그아웃 처리됩니다.
인증
비밀번호 재확인
애플리케이션을 개발하다 보면, 민감한 작업을 수행하거나 보안이 필요한 영역에 접근하기 전에 사용자에게 비밀번호를 다시 한 번 확인하도록 요구해야 할 때가 있습니다. Laravel은 이 기능을 손쉽게 구현할 수 있도록 내장 미들웨어를 제공합니다. 구현을 위해서는 두 개의 라우트가 필요합니다. 하나는 비밀번호 확인 폼을 보여주는 라우트이고, 다른 하나는 입력된 비밀번호를 검증하고 사용자를 원래 목적지로 리디렉션하는 라우트입니다.
NOTE
아래 문서는 비밀번호 재확인 기능을 직접 구현하는 방법을 설명합니다. 빠르게 시작하고 싶다면 Laravel 애플리케이션 스타터 킷을 사용하세요. 스타터 킷은 이 기능을 기본으로 포함하고 있습니다.
설정
사용자가 비밀번호를 확인하면, 이후 3시간 동안은 다시 확인을 요구하지 않습니다. 이 유효 시간은 config/auth.php 설정 파일의 password_timeout 값을 변경하여 조정할 수 있습니다.
라우팅
비밀번호 확인 폼
먼저, 사용자에게 비밀번호 입력을 요청하는 뷰를 반환하는 라우트를 정의합니다.
Route::get('/confirm-password', function () {
return view('auth.confirm-password');
})->middleware('auth')->name('password.confirm');이 라우트가 반환하는 뷰에는 password 필드를 포함한 폼이 있어야 합니다. 또한 사용자가 보안 영역에 진입하려고 하며 비밀번호 확인이 필요하다는 안내 문구를 함께 표시하는 것이 좋습니다.
비밀번호 검증 처리
다음으로, 비밀번호 확인 폼에서 제출된 요청을 처리할 라우트를 정의합니다. 이 라우트는 비밀번호를 검증하고, 유효하다면 사용자를 원래 목적지로 리디렉션하는 역할을 합니다.
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redirect;
Route::post('/confirm-password', function (Request $request) {
if (! Hash::check($request->password, $request->user()->password)) {
return back()->withErrors([
'password' => ['입력한 비밀번호가 일치하지 않습니다.']
]);
}
$request->session()->passwordConfirmed();
return redirect()->intended();
})->middleware(['auth', 'throttle:6,1']);이 라우트의 처리 흐름을 살펴보면 다음과 같습니다.
Hash::check()를 사용해 요청으로 받은password가 현재 인증된 사용자의 비밀번호와 일치하는지 확인합니다.- 비밀번호가 유효하면
passwordConfirmed()메서드를 호출합니다. 이 메서드는 세션에 타임스탬프를 기록하여, Laravel이 사용자가 마지막으로 비밀번호를 확인한 시점을 파악할 수 있게 합니다. - 마지막으로
redirect()->intended()를 통해 사용자를 원래 접근하려 했던 목적지로 리디렉션합니다.
throttle:6,1 미들웨어는 브루트포스 공격을 방지하기 위해 1분 동안 최대 6번의 요청만 허용합니다.
라우트 보호
비밀번호 재확인이 필요한 라우트에는 반드시 password.confirm 미들웨어를 적용해야 합니다. 이 미들웨어는 Laravel 기본 설치에 포함되어 있으며, 사용자가 접근하려는 목적지를 세션에 자동으로 저장합니다. 그런 다음 사용자를 password.confirm이라는 이름이 지정된 라우트로 리디렉션하여 비밀번호를 확인하게 하고, 확인이 완료되면 원래 목적지로 돌려보냅니다.
Route::get('/settings', function () {
// ...
})->middleware(['password.confirm']);
Route::post('/settings', function () {
// ...
})->middleware(['password.confirm']);NOTE
GET과 POST 라우트 모두에 password.confirm 미들웨어를 적용해야 합니다. 한쪽에만 적용하면 POST 요청이 직접 전송되는 경우 비밀번호 확인을 우회할 수 있습니다.
커스텀 가드 추가하기
Auth 파사드의 extend 메서드를 사용하면 직접 인증 가드를 정의할 수 있습니다. extend 호출은 서비스 프로바이더 안에 두어야 합니다. Laravel에는 기본적으로 AppServiceProvider가 포함되어 있으므로, 그곳에 코드를 추가하면 됩니다.
<?php
namespace App\Providers;
use App\Services\Auth\JwtGuard;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
// ...
/**
* 애플리케이션 서비스를 부트스트랩합니다.
*/
public function boot(): void
{
Auth::extend('jwt', function (Application $app, string $name, array $config) {
// Illuminate\Contracts\Auth\Guard 구현체를 반환해야 합니다.
return new JwtGuard(Auth::createUserProvider($config['provider']));
});
}
}위 예시처럼, extend에 전달하는 콜백은 반드시 Illuminate\Contracts\Auth\Guard 인터페이스의 구현체를 반환해야 합니다. 이 인터페이스에는 커스텀 가드를 정의하기 위해 구현해야 할 몇 가지 메서드가 포함되어 있습니다.
커스텀 가드를 정의했다면, auth.php 설정 파일의 guards 항목에서 해당 가드를 참조할 수 있습니다.
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],클로저 기반 요청 가드
HTTP 요청 기반의 커스텀 인증을 가장 간단하게 구현하는 방법은 Auth::viaRequest 메서드를 사용하는 것입니다. 별도의 클래스 없이 클로저 하나로 인증 로직을 빠르게 정의할 수 있습니다.
AppServiceProvider의 boot 메서드 안에서 Auth::viaRequest를 호출합니다. 첫 번째 인수에는 커스텀 가드를 식별할 드라이버 이름(임의의 문자열)을 지정하고, 두 번째 인수에는 HTTP 요청을 받아 사용자 인스턴스 또는 인증 실패 시 null을 반환하는 클로저를 전달합니다.
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
/**
* 애플리케이션 서비스를 부트스트랩합니다.
*/
public function boot(): void
{
Auth::viaRequest('custom-token', function (Request $request) {
return User::where('token', (string) $request->token)->first();
});
}커스텀 인증 드라이버를 정의했다면, auth.php 설정 파일의 guards 항목에 드라이버로 등록합니다.
'guards' => [
'api' => [
'driver' => 'custom-token',
],
],이후 라우트에 인증 미들웨어를 적용할 때 해당 가드를 지정하면 됩니다.
Route::middleware('auth:api')->group(function () {
// ...
});커스텀 유저 프로바이더 추가하기
사용자 정보를 전통적인 관계형 데이터베이스가 아닌 다른 저장소(예: MongoDB, Redis 등)에 보관한다면, 커스텀 유저 프로바이더를 직접 구현해야 합니다. Auth 파사드의 provider 메서드를 사용하면 커스텀 프로바이더를 등록할 수 있습니다. 프로바이더 리졸버는 반드시 Illuminate\Contracts\Auth\UserProvider 구현체를 반환해야 합니다.
<?php
namespace App\Providers;
use App\Extensions\MongoUserProvider;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
// ...
/**
* 애플리케이션 서비스를 부트스트랩합니다.
*/
public function boot(): void
{
Auth::provider('mongo', function (Application $app, array $config) {
// Illuminate\Contracts\Auth\UserProvider 인스턴스를 반환합니다...
return new MongoUserProvider($app->make('mongo.connection'));
});
}
}provider 메서드로 프로바이더를 등록한 뒤에는 auth.php 설정 파일에서 새 드라이버를 사용하도록 전환합니다. 먼저 새 드라이버를 사용하는 providers 항목을 정의합니다.
'providers' => [
'users' => [
'driver' => 'mongo',
],
],그리고 이 프로바이더를 guards 설정에서 참조합니다.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],UserProvider 컨트랙트
Illuminate\Contracts\Auth\UserProvider 구현체는 MySQL, MongoDB 등 영속 저장소에서 Illuminate\Contracts\Auth\Authenticatable 구현체를 가져오는 역할을 합니다. 이 두 인터페이스 덕분에 사용자 데이터가 어떤 방식으로 저장되어 있든, 어떤 클래스로 표현되든 상관없이 Laravel 인증 메커니즘이 일관되게 동작할 수 있습니다.
Illuminate\Contracts\Auth\UserProvider 컨트랙트를 살펴봅시다.
<?php
namespace Illuminate\Contracts\Auth;
interface UserProvider
{
public function retrieveById($identifier);
public function retrieveByToken($identifier, $token);
public function updateRememberToken(Authenticatable $user, $token);
public function retrieveByCredentials(array $credentials);
public function validateCredentials(Authenticatable $user, array $credentials);
public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false);
}각 메서드의 역할은 다음과 같습니다.
-
retrieveById— MySQL의 자동 증가 기본키처럼 사용자를 식별하는 키를 받아, 해당 키에 맞는Authenticatable구현체를 반환합니다. -
retrieveByToken— 고유한$identifier와 "로그인 상태 유지" 토큰($token)으로 사용자를 조회합니다. 이 토큰은 보통remember_token컬럼에 저장됩니다. 토큰이 일치하는Authenticatable구현체를 반환해야 합니다. -
updateRememberToken—$user인스턴스의remember_token을 새$token으로 갱신합니다. "로그인 상태 유지" 인증이 성공하거나 사용자가 로그아웃할 때 호출됩니다. -
retrieveByCredentials—Auth::attempt에 전달된 자격증명 배열을 받아, 저장소에서 해당 사용자를 조회합니다. 일반적으로$credentials['username']값으로 사용자 레코드를 검색하는 쿼리를 실행하고Authenticatable구현체를 반환합니다. 이 메서드에서 비밀번호 검증은 절대 수행하지 않아야 합니다. -
validateCredentials—$user와$credentials를 비교해 사용자를 인증합니다. 보통Hash::check를 사용해$user->getAuthPassword()와$credentials['password']를 비교하고, 유효 여부에 따라true또는false를 반환합니다. -
rehashPasswordIfRequired— 필요한 경우 사용자의 비밀번호를 재해싱합니다. 보통Hash::needsRehash로 재해싱 필요 여부를 확인한 뒤, 필요하다면Hash::make로 비밀번호를 다시 해싱하고 저장소의 레코드를 업데이트합니다.
Authenticatable 컨트랙트
UserProvider의 각 메서드를 살펴봤으니, 이제 Authenticatable 컨트랙트를 살펴볼 차례입니다. 유저 프로바이더는 retrieveById, retrieveByToken, retrieveByCredentials 메서드에서 이 인터페이스의 구현체를 반환해야 합니다.
<?php
namespace Illuminate\Contracts\Auth;
interface Authenticatable
{
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPasswordName();
public function getAuthPassword();
public function getRememberToken();
public function setRememberToken($value);
public function getRememberTokenName();
}인터페이스는 비교적 단순합니다.
| 메서드 | 역할 |
|---|---|
getAuthIdentifierName() | 기본키 컬럼명을 반환합니다 (예: id) |
getAuthIdentifier() | 사용자의 기본키 값을 반환합니다 |
getAuthPasswordName() | 비밀번호 컬럼명을 반환합니다 (예: password) |
getAuthPassword() | 사용자의 해싱된 비밀번호를 반환합니다 |
getRememberToken() | 현재 "로그인 상태 유지" 토큰을 반환합니다 |
setRememberToken($value) | "로그인 상태 유지" 토큰을 설정합니다 |
getRememberTokenName() | 토큰 컬럼명을 반환합니다 (예: remember_token) |
이 인터페이스 덕분에 어떤 ORM이나 저장소 추상화 레이어를 사용하더라도 인증 시스템이 일관되게 동작합니다. Laravel은 기본적으로 이 인터페이스를 구현한 App\Models\User 클래스를 app/Models 디렉터리에 제공합니다.
인증
비밀번호 자동 재해싱
Laravel의 기본 비밀번호 해싱 알고리즘은 bcrypt입니다. bcrypt의 "작업 인수(work factor)"는 config/hashing.php 설정 파일이나 BCRYPT_ROUNDS 환경 변수를 통해 조정할 수 있습니다.
시간이 지남에 따라 CPU/GPU 성능이 향상되므로, bcrypt 작업 인수도 점진적으로 높이는 것이 일반적인 보안 관행입니다. 작업 인수를 높이면, Laravel은 사용자가 스타터 킷 또는 attempt 메서드를 통해 직접 인증할 때 기존 비밀번호를 자동으로 새 설정에 맞게 재해싱합니다.
NOTE
자동 재해싱은 사용자가 로그인하는 시점에 투명하게 처리되며, 대부분의 경우 애플리케이션 동작에 영향을 주지 않습니다.
이 동작을 비활성화하려면 먼저 hashing 설정 파일을 퍼블리시합니다:
php artisan config:publish hashing퍼블리시된 설정 파일에서 rehash_on_login 값을 false로 변경합니다:
'rehash_on_login' => false,이벤트
Laravel은 인증 과정에서 다양한 이벤트를 디스패치합니다. 아래 이벤트들에 대해 리스너를 등록하여 인증 흐름의 각 단계에 원하는 로직을 추가할 수 있습니다.
| 이벤트 이름 |
|---|
Illuminate\Auth\Events\Registered |
Illuminate\Auth\Events\Attempting |
Illuminate\Auth\Events\Authenticated |
Illuminate\Auth\Events\Login |
Illuminate\Auth\Events\Failed |
Illuminate\Auth\Events\Validated |
Illuminate\Auth\Events\Verified |
Illuminate\Auth\Events\Logout |
Illuminate\Auth\Events\CurrentDeviceLogout |
Illuminate\Auth\Events\OtherDeviceLogout |
Illuminate\Auth\Events\Lockout |
Illuminate\Auth\Events\PasswordReset |
NOTE
예를 들어 Login 이벤트 리스너를 등록하면 사용자가 로그인할 때마다 접속 로그를 기록하거나 알림을 발송하는 등의 부가 작업을 깔끔하게 처리할 수 있습니다. 이벤트 리스너 등록 방법은 이벤트 문서를 참고하세요.