Home 라라벨로 배우는 php 웹 프로그래밍
Post
Cancel

라라벨로 배우는 php 웹 프로그래밍

라라벨로 배우는 실전 PHP 웹 프로그래밍

PART 1 라라벨 입문

9. 사용자 인증

9.1 HTTP의 무상태 특성

웹에서는 같은 사용자가 동일한 서버에 여러번 접근 하였더라도, 연속된 접근이 같은 사람으로 부터 왔다는것은 구분할 수 없다. 이런 무상태(stateless)는 HTTP 프로토콜의 가장 큰 특징이다.

웹에서는 사용자가 로그인 하면 서버에서는 세션(session)이라 부르는 이름표를 하나 만들고, HTTP 쿠리(cookie) 메커니즘을 이용해서 세션이 만료되거나 사용자가 명시적으로 로그아웃할때까지 클라이언트와 이름표를 계속 주고받는다. 이 방법으로 서버는 클라이언트를 식별하고, 상태를 우지한다. 라라벨은 web 미들웨어 그룹에 속한 모든 라우트에서 세션을 유지한다.

9.2 기본다지기

로그인 종작 원리를 익히자

9.2.1 User 모델

User 모델과 마이그레이션은 라라벨에 기본적으로 포함되어 있다.

app/models/User.php

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
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

name, email, password 열은 대량 할당이 가능하다. $hidden 프로터피에는 조회 쿼리에서 제외할 열을 정의한다. App\Models\User::get() 쿼리를 하면 password , remember_token 값은 표시되지 않는다.

다른 클래스에서도 접근하기 위해 public 가시성을 가진다. public으로 선언된 모델 프로퍼티 값을 은익하는 방법이 $hidden이다. 물론 App\Models\User::find(1)->password와 같이 직접 접근하면 값을 읽거나 쓸 수 있다.

database/migrations/2014_10_12_000000_create_users_table.php

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
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

rememberToken()은 string(‘remember_token’,100)->nullable()의미를 가진 도우미 메서드다. users.remember_token 열은 사용자 로그인을 기억할 때 사용된디.

팅커 콘솔로 사용자를 만들어 본다

새로운 사용자 만들기

1
2
3
4
5
6
7
8
9
10
$ php artisan tinker
>>> $user = App\Models\User::create(['name'=> 'John','email'=>'test@test.com','password' => bcrypt('test')]);
=> App\Models\User {#4296
     name: "John",
     email: "test@test.com",
     updated_at: "2021-01-20 13:52:27",
     created_at: "2021-01-20 13:52:27",
     id: 1,
   }
>>> 

9.2.2 사용자 인증 구현

라우팅 파일만으로 사용자 인증을 구현

routes/web.php ```php <?php

use Illuminate\Support\Facades\Route;

Route::get(‘/’, ‘WelcomeController@index’);

Route::get(‘auth/login’, function () { $credentials = [ ‘email’ => ‘test@test.com’, ‘password’=>’test’ ];

1
2
3
4
5
if (! auth()-> attempt($credentials)){
    return '로그인 정보가 올바르지 않습니다.';
}

return redirect('protected'); });

Route::get(‘protected’, function () { dump(session()->all());

1
2
3
4
5
if(!auth()->check()){
    return "누구세요";
}

return '어서 오세요'.auth()->user()->name; });

Route::get(‘auth/logout’, function () { auth()->logout();

1
return "안녕히가세요"; });
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
- GET auth/login 라우트

credentials 변수에 사용자 로그인에 필요한 정보를 하드코드로 담았다. auth()는 도우미 함수다. 사용자를 인증할 때는 attempt(array $credentials = [] , bool $remember = false)메서드를 이용한다. 메서드의 두 번째 인자에 true를 주면, 마이그레이션에서 봤던 remember_token 열과 같이 동작해서 사용자 로그인을 기억할 수 있다.

auth() 도우미 대신 Auth::attempt()와 같이 파사드를 이용할 수도 있다. attempt() 메서드는 넘겨 받은 $credentials 정보를 데이터베이스 조회를 하기 전에 미리 해싱해서 비교할 준비를 한다. 로그인에 성공하면 세션에 사용자 정보를 기록한다.

이 로직은 사용자 정보가 정확하지 않으면 오류 메세지를 표시한다. 로그인에 성공하면 /protected 로 사용자를 리디렉션 한다.

- GET protected 라우트

check() 메서드는 URL을 요청한 브라우저(사용자)가 로그인 상태명 true를 반환한다. user() 메서드는 로그읺나 사용자의 클래스 인스탄스를 반환한다. 그러므로 auth()->uset()->name과 같이 쓸수 있다.

check() 메서드가 로그인 했는지 어떻게 알았을까? 이는 앞서 배운 쿠키 메커니즘으로 알 수 있다. 크롬 개발자 도구에서 HTTP 요청 해더에서 laravel_session 키와 값을 찾아보자.

이 키의 값은 직전의 요청에 HTTP 응답 헤더로 받은 값이다. 참고로 전역 미들웨어인 App\Http\Middleware\EncyptCookies가 이 값을 암복호화한다. 쿠키 변조를 막으려는 조치다.

dump(session()->all()) 은 세션에 저장된 값을 덤프하는 코드다. 로그인했을 때와 로그인하지 안았을 때의 차이점을 찾아보자. 덤프 결과에서 login_web_RANDOM_NUMBER 키에 사용자에 해당하는 기본 키 값이 담겨 있다. 이 키는 로그인했을 때만 존재한다.

정리하면 라라벨은 laravle_ssesion 키를 가진 쿠키와 login_web_RANDOM_NUMBER 세션 키를 이용해서 사용자 로그인 여부를 핀단한다. 쿠키에 사용할 키는 config/session.php에서 변경할 수 있다.

- GET auth/logout

로그아웃은 logout()메서드를 사용한다. 로그아웃하면 세션을 폐기한다.

#### 9.2.3 auth 미들웨어

protected 에 if(!auth()->check()) 블락이 없으면, auth()->user() 값이 null이기 때문에, 오류가 발생한다. (null->name은 불가능)

auth() 미들웨어를 사용하면 if절을 사용하지 않고 다른 위치로 이동시킬 수 있다.

> routes/web.php

```php
<?php

use Illuminate\Support\Facades\Route;

Route::get('/', 'WelcomeController@index');

Route::get('auth/login', function () {
    $credentials = [
        'email' => 'test@test.com',
        'password'=>'test1'
    ];

    if (! auth()-> attempt($credentials)){
        return '로그인 정보가 올바르지 않습니다.';
    }

    return redirect('protected');
});

Route::get('protected', ['middleware'=>'auth', function () {
}]);

Route::get('auth/logout', function () {
    auth()->logout();

    return "안녕히가세요";
});

myapp/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<?php

namespace Illuminate\Auth\Middleware;

use Closure;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Contracts\Auth\Factory as Auth;
use Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests;

class Authenticate implements AuthenticatesRequests
{
    /**
     * The authentication factory instance.
     *
     * @var \Illuminate\Contracts\Auth\Factory
     */
    protected $auth;

    /**
     * Create a new middleware instance.
     *
     * @param  \Illuminate\Contracts\Auth\Factory  $auth
     * @return void
     */
    public function __construct(Auth $auth)
    {
        $this->auth = $auth;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string[]  ...$guards
     * @return mixed
     *
     * @throws \Illuminate\Auth\AuthenticationException
     */
    public function handle($request, Closure $next, ...$guards)
    {
        $this->authenticate($request, $guards);

        return $next($request);
    }

    /**
     * Determine if the user is logged in to any of the given guards.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  array  $guards
     * @return void
     *
     * @throws \Illuminate\Auth\AuthenticationException
     */
    protected function authenticate($request, array $guards)
    {
        if (empty($guards)) {
            $guards = [null];
        }

        foreach ($guards as $guard) {
            if ($this->auth->guard($guard)->check()) {
                return $this->auth->shouldUse($guard);
            }
        }

        $this->unauthenticated($request, $guards);
    }

    /**
     * Handle an unauthenticated user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  array  $guards
     * @return void
     *
     * @throws \Illuminate\Auth\AuthenticationException
     */
    protected function unauthenticated($request, array $guards)
    {
        throw new AuthenticationException(
            'Unauthenticated.', $guards, $this->redirectTo($request)
        );
    }

    /**
     * Get the path the user should be redirected to when they are not authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return string|null
     */
    protected function redirectTo($request)
    {
        //
    }
}

myapp/app/Http/Middleware/Authenticate.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;

class Authenticate extends Middleware
{
    /**
     * Get the path the user should be redirected to when they are not authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return string|null
     */
    protected function redirectTo($request)
    {
        if (! $request->expectsJson()) {
            return 'auth/login';
        }
    }
}

9.3 라라벨 내장 사용자 인증

콘솔레어 라티즌 명령을 실행한다.

라라벨 내장 사용자 인증 기능 초기화

8버전에서 실패…

This post is licensed under CC BY 4.0 by the author.

라라벨로 배우는 php 웹 프로그래밍

Java_Interview_Questions

Comments powered by Disqus.

Trending Tags