WordPress FTP 인증 생략

FTP 인증 생략

wp-config.php 파일을 열어 아래 코드를 추가한다.

define(‘FS_METHOD’, ‘direct’);

필요한 폴더에 권한 부여

업데이트나 설치는 모두 파일을 쓰는 것이다. 폴더를 읽을 수 있는 권한도 당연히 필요하겠지. 권한이 필요한 폴더는 다음과 같다.

  1. wordpress 폴더
  2. wp-content/
  3. wp-content/plugins/
  4. wp-content/upgrade/ (워드프레스 코어 업그레이드 필요)

권한을 변경하는 명령어는 다음과 같다.

$ sudo chmod 755 [폴더명]

소유자 확인

 

웹서버 서비스 계정 확인

$ cat /etc/issue
Ubuntu 14.04.1 LTS \n \l
$ vim /etc/apache2/apache2.conf
# These need to be set in /etc/apache2/envvars
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
$ cat /etc/apache2/envvars
export APACHE_RUN_USER=www-data
export APACHE_RUN_GROUP=www-data

소유자 변경

소유자를 변경하는 명령어는 다음과 같다.

sudo chown [계정명]:[그룹명] [파일명]

예를들어 wp-content/ 의 소유자를 변경한다면 아래와 같이 입력한다.

sudo chown www-data:www-data wp-content

그러면 그 폴더의 소유자만 쏙 바뀐다. 그런데… 이거 상당히 귀찮다. 그냥 워드프레스 폴더와 그 내부 모든 파일의 소유자를 www-data로 바꿀 수는 없을까? 있다. 바로 -R옵션을 사용하는 것이다.

sudo chown -R www-data:www-data wordpress

그러면 워드프레스 이하 모든 폴더와 파일의 소유자가 바뀐다. 이제 755 접근권한을 가진 폴더나 파일에 워드프레스가 접근 할 수 있다. 정확히는 아파치를 사용하여 동작하는 모든 서비스가 접근 할 수 있는 것이지만 거기까지는 생각하지 말자. 자 이제 워드프레스에 접속해서 테마와 플러그인을 설치든 업데이트든 마음껏 해보자. 제대로 따라오기만 했다면 인증없이 그리고 접근 오류 따위도 없이 완료될 것이다.

작은 문제점

완벽한 것 같지만 이렇게하면 작은 문제점이 발생한다. 바로 내 계정으로 FTP에 접속하여 파일을 업로드하거나 다운로드 할 수 없다는 것이다… SSH로 접속하면 sudo 명령어를 통해 루트 권한을 잠깐 부여받아 뭐든 수행할 수 있지만 FTP는 다르다. 그럼 이 문제는 어떻게 해결해야 할까?

두 가지 방법이 있다.

[yourId]:[www-data] 775

하나는 폴더의 소유자는 자신의 계정으로 하고, 워드프레스가 파일쓰기가 필요한 폴더의 접근권한을 775로 바꾸는 것이다. 즉 www-data 그룹의 계정은 쓰기가 가능하도록 하는 것이다.

www-data 그룹에 사용자 계정 추가

이건 내가 사용하고 있는 방법인데 일단 전체적으로는 소유자와 그룹 모두 www-data로 해놓고, www-data 그룹에 나의 계정을 추가하고 내가 FTP로 접속하여 파일을 업/다운로드 할 폴더만 775 권한을 주는 것이다.

그룹에 사용자를 추가하는 명령어는 다음과 같다. 기존 그룹을 변경하는 것이 아니라 보조 그룹에 넣는 방법이다.

$ sudo usermod -G [userId]:[group]

처음에 설명한 파일의 접근권한과 소유자에 대한 이해만 확실히 하고 있다면 자신의 입맛대로 골라서 문제를 해결 할 수 있을 것이다. 번거롭게 느껴질지 몰라도 파일 하나 하나에 대한 소유권과 접근권한을 사용자가 강력하게 통제할 수 있는 장점 덕분에 대부분의 서버가 유닉스/리눅스 기반이지 않을까? 생각한다.

참고 문헌

워드프레스 FTP 인증 오류 해결 방법

Advertisements

MySQL 외부 접속 허용 설정

1. 문제상황
  • MySQL을 설치하면 기본적으로 로컬(localhost)에서만 접속이 가능하고 외부에서는 접속이 불가능하게 되어 있다.
외부에서 접속해보면 다음과 같은 오류 메시지가 나온다.
Host '135.79.246.80' is not allowed to connect to this MySQL server
  • Toad for MySQL과 같은 DB 관리 도구를 사용하여 DB에 원격으로 접속하려면 허용해주는 로컬 작업이 필요하다.
  • 여기서는 root를 원격에서 접속할 수 있도록 설정한다. 이것을 응용하면 다른 계정에도 적용할 수 있다..

2. 확인

  • 로컬에서 접속하여 아래 쿼리를 날려보면 localhost가 나온다.
mysql> SELECT Host,User,authentication_string FROM mysql.user;
+----------------+------------------+-------------------------------------------+
| Host           | User             | authentication_string                     |
+----------------+------------------+-------------------------------------------+
| localhost      | root             | *8024A6913C57E024BDFC6E813A57DFB924E6803A |
| 127.0.0.1      | root             | *8024A6913C57E024BDFC6E813A57DFB924E6803A |
| ::1            | root             | *8024A6913C57E024BDFC6E813A57DFB924E6803A |
| localhost      | debian-sys-maint | *02CE4A6D8F13BE579AC2468F0357B9D1468025A7 |
+----------------+------------------+-------------------------------------------+
즉 root 계정으로는 로컬에서만 접속가능하다.
(같은 방법으로 root 대신 다른 사용자명도 조회할 수 있다.)

3 변경

모든 IP 허용
INSERT INTO mysql.user (host,user,authentication_string,ssl_cipher, x509_issuer, x509_subject) VALUES ('%','root',password('패스워드'),'','','');
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;
IP 대역 허용 ( 예: 111.222.xxx.xxx )
  • 다음과 같이 설정하면 111.222로 시작하는 모든 IP가 허용된다.
INSERT INTO mysql.user (host,user,authentication_string,ssl_cipher, x509_issuer, x509_subject) VALUES ('111.222.%','root',password('패스워드'),'','','');
GRANT ALL PRIVILEGES ON *.* TO 'root'@'111.222.%';
FLUSH PRIVILEGES;
특정 IP 1개 허용 ( 예: 111.222.33.44 )
INSERT INTO mysql.user (host,user,authentication_string,ssl_cipher, x509_issuer, x509_subject) VALUES ('111.222.33.44','root',password('패스워드'),'','','');
GRANT ALL PRIVILEGES ON *.* TO 'root'@'111.222.33.44';
FLUSH PRIVILEGES;

4 원래 상태로 복구

  • 모든 IP를 허용한 경우 다음과 같이 원래 상태로 복구할 수 있다.
DELETE FROM mysql.user WHERE Host='%' AND User='root';
FLUSH PRIVILEGES;

5. LISTEN IP 대역 변경

16px-Crystal_Clear_app_xmag.svg.png MySQL bind-address 변경 문서를 참고하십시오.
root@zetawiki:~# netstat -ntlp | grep mysqld
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      7931/mysqld
root@zetawiki:~# vi /etc/mysql/my.cnf
#bind-address            = 127.0.0.1
bind-address            = 0.0.0.0
root@zetawiki:~# service mysql restart
mysql stop/waiting
mysql start/running, process 8190
root@zetawiki:~# netstat -ntlp | grep mysqld
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      8190/mysqld

 

Laravel 5 Https 적용하기

  • 작업 조건
    • php
    • laravel 5.3
  • 작업 내용
    • laravel에 https route 적용하기
  • 작업 과정
    • 1. 미들웨어 ForceSSL를 생성합니다.
      php artisan make:middleware ForceSSL
    • 2. 미들웨어의 형태는 다음과 같습니다.
    • <?php
      
      namespace App\Http\Middleware;
      
      use Closure;
      
      class ForceSSL
      {
      
          public function handle($request, Closure $next)
          {
      
              if (!$request->secure()) {
                  return redirect()->secure($request->getRequestUri());
              }
      
              return $next($request);
          }
      }
    • 로컬 개발 및 프로덕션 모두에 대해 HTTPS설정을 사용하므로 환경을 기반으로 필터링 할 필요가 없습니다.

      다음을 App\kernel.php에 추가하면 SSL을 강제 적용할 경로 그룹을 선택하고 선택할 수 있습니다.

    •     protected $routeMiddleware = [
          'auth' => \App\Http\Middleware\Authenticate::class,
          'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
          'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
          'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
          'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
          'forceSSL' => \App\Http\Middleware\ForceSSL::class,
      ];
  • 작업 과정 중 참고사항
  • 작업 중 발생한 문제 해결
  • 작업과 관련된 주제
  • 참고 문헌

Jquery Plugin 개발하기

 

1. Why Jquery Plugin?

다음과 같은 두가지 이유가 있습니다.

  • 일관된 코드 스타일을 유지한다.
  • jQuery의 기반 코드를 잘 활용한다.

jQuery가 자바스크립트 라이브러리로서 널리 사용되고 있기에 스크립트 개발방식에 상당한 영향을 주고 있습니다. 예제1을 살펴보겠습니다. 셀렉터는 엘리먼트 확장 집합의 형태로 표현하고 있습니다. 그리고 jQuery 메소드와 메소드 체인을 셀렉터(확장 집합)에 적용합니다. 이런 코드 스타일은 jQuery를 적용한 스크립트에서 대표적으로 사용되는 스타일입니다.

예제1

$(this).parents().find("input").val();

개발 할 때 이러한 스타일을 반드시 고수해야 하는 것은 아닙니다. 이와 다른 스타일로도 작성이 가능합니다. 하지만 일반적으로 경험많은 개발자들은 프로젝트를 진행하거나, 협업을 하는 경우 코드의 일관성을 유지하는것이 좋다고 조언합니다. 자신의 개발하는 코드를 일반 자바스크립트 함수가 아닌 jQuery 플러그-인으로 제작하면 사이트 전체에 일관된 코드 스타일을 유지할 수 있습니다. 코드 스타일이 일관된다면 코드에 대한 이해가 쉽고 유지보수에도 용이합니다.

jQuery 플러그-인을 제작하는 두번째 이유는 jQuery가 제공하는 강력한 기능(셀렉터, 메소드)을 활용할 수 있다는 점입니다. 이미 jQuery에는 우리에게 익숙하고, 강력한 도구가 많이 있습니다. 이를 두고 처음부터 다시 코드를 작성할 이유가 없습니다.

결론적으로 jQuery 도구 재사용이 가능한 스크립트 환경에서는 jQuery 플러그-인으로 작성하는 것이 현명한 방법이라 할 수 있습니다.

플러그-인 제작

간단한 jQuery 플러그-인을 제작해 보겠습니다. 자바스크립트 함수를 jQuery Object 인스턴스 프로퍼티로 추가하여 제작했습니다. 그 내용은 예제2와 같습니다.

예제2

$.say = function(what) { alert('I Say ' + what); }

마치 자바스크립트 함수를 선언하고 객체 프로퍼티로 할당하는 것과 같이 쉽고 단순합니다.

[플러그-인에서 ‘$’별칭 사용]

jQuery를 사용하는 개발자라면 대부분 ‘$’별칭을 사용합니다. 코드 작성시 편리하게 사용되고 ‘$’로 작성된 코드가 보다 읽기 편하기 때문입니다. 하지만 플러그-인에서 ‘$’별칭을 사용할 수 있다고 단정지을 수 없습니다. 완성된 플러그-인이 배포되어 다른 환경에서 사용이 된다고 가정 해보겠습니다. 만약 그 환경이 $.noConflict() 메소드를 사용하여 ‘$’별칭을 모두 양도한다면 위와 같이 작성된 플러그-인은 작동하지 않습니다.

예제3

jQuery.say = function(what) { alert('I Say ' + what); }  

예제3과 같이 작성한다면 ‘$’별칭의 충돌을 피할 수 있습니다. 하지만 이미 ‘$’별칭에 익숙하고 그 장점을 포기할 수 없으면 예제4와 같이 정의합니다.

예제4

(function($) {
    $.say = function(what) { alert('I Say ' + what); }
})(jQuery);

이처럼 ‘$’를 플러그-인 내부의 지역 변수로 정의하여 사용하면 충돌을 피하면서도 ‘$’별칭을 사용할수 있습니다. 이렇게 함수를 정의해 바로 사용하는 문법을 즉석 호출 함수 표현식(IIFE, Immediately Invoked Function Expression)이라 합니다. 앞으로 보여드릴 플러그-인 예제는 이러한 형식을 사용하고 있습니다.

[전역함수]

jQuery 전역함수는 실제로 jQuery 객체의 메소드지만, 현실적으로 보면 jQuery 네임스페이스의 함수입니다. 따라서 jQuery 네임 스페이스에 함수를 작성하면 일반 전역함수와의 충돌 가능성은 없습니다. 단 jQuery 메소드와 이름이 충돌하는지의 여부만 신경써주면 됩니다. jQuery 라이브러리에서 제공하는 전역함수 중에는 $.each(), $.map(), $.grep()과 같은 다양한 유틸리티 메소드(utility method)가 있습니다.

간단한 유틸리티 메소드를 직접 제작해 보겠습니다.

예제5

(function ($) {
    $.sum = function(array) {
        var total = 0;
        $.each(array, function(index, value) {
        value = $.trim(value);
        value = parseFloat(value) || 0;

        total += value;
    });
    return tatal;
};
})(jQuery);

(function ($) {
    $.average = function(array) {
        if($.isArray(array)) {
            return $.sum(array) / array.length;
        }
        return '';
    };
})(jQuery);

배열을 받아 총계를 리턴하는 함수와 평균을 리턴하는 함수를 jQuery 객체의 프로퍼티에 추가하여 간단히 플러그-인을 제작했습니다. 이 플러그-인들은 예제6과 같이 사용할 수 있습니다.

예제6

$.sum();
$.average();

이렇게 제작된 전역함수는 jQuery 네임스페이스 내 같은 이름을 갖는 함수와 충돌할 수 있습니다. 이를 예방하기 위해 전역함수를 하나의 객체로 캡슐화(encapsulation) 할 수 있습니다.

예제7

(function ($) {
    $.mathUtils = {
        sum: function(array) {
            var total = 0;
            $.each(array, function(index, value) {
                value = $.trim(value);
                value = parseFloat(value) || 0;

                total += value;
            });
            return tatal;
        },
        average: function(array) {
            if($.isArray(array)) {
                return $.sum(array) / array.length;
            }
            return '';
        };
})(jQuery);

예제7과 같은 패턴은 jQuery.mathUtils 네임스페이스를 생성하고 정의된 함수를 jQuery 객체의 프로퍼티인 mathUtils 객체의 메소드가 됩니다. 이렇게 정의된 플러그인은 예제8과 같이 사용할 수 있습니다.

예제8

$.mathUtils.sum(sum);
$.mathUtils.average(average);

[객체 메소드]

앞에서 jQuery 전역함수를 만들어 보았습니다. 하지만 대부분의 jQuery 내장 기능은 객체 메소드로 제공됩니다. 이번에는 DOM일부를 조작하는 함수인 객체 메소드를 제작해 보겠습니다.

예제9

(function($) {
    $.fn.swapClass = function(class1, class2) {
        if (this.hasClass(class1)) {
            this.removeClass(class1).addClass(class2);
        }
        else if (this.hasClass(class2)) {
            this.removeClass(class2).addClass(class1);
        }
    };
})(jQuery);

jQuery객체를 확장했던 전역함수와는 달리 객체 메소드는 jQuery.fn 객체를 확장하고 있습니다.(jQuery.fn은 jQuery.prototype의 별칭입니다.) 위와 같이 제작한 플러그인은 지정된 DOM 엘리먼트의 class를 변경하는 기능을 제공하고있습니다. 사용하는 방법은 예제10과 같습니다.

예제10

$('div').swapClass('one', 'two');

기존의 <div>엘리먼트의 class가 ‘one’ 이라면 ‘two’ 로 ‘two’ 라면 ‘one’로 변경이 된다고 예측할 수 있습니다.

[묵시적 반복]

앞에서 소개된 객체 메소드는 DOM 엘리먼트 집합중 최초의

엘리먼트만 적용이 됩니다. 하지만 일반적으로 사용되는 jQuery 함수는 jQuery 선택자 표현식이 0개 또는 1개 이상의 요소와 매칭이 됩니다. 즉, jQuery 함수는 다수의 엘리먼트에 함수의 기능이 적용되어야 합니다. 따라서 플러그-인을 설계할 때 jQuery 선택자가 복수인 경우를 모두 감안해야 합니다. .each() 메소드를 이용하여 묵시적인 반복(implicit iteration)을 수행하도록 플러그-인을 수정하겠습니다.예제11

(function($) {
    $.fn.swapClass = function(class1, class2) {
        this.each(function() {
            var $element = $(this);
            if ($element.hasClass(class1)) {
                $element.removeClass(class1).addClass(class2);
            }
            else if ($element.hasClass(class2)) {
                $element.removeClass(class2).addClass(class1);
            }
        });
    };
})(jQuery);

예제11에서 this 키워드의 의미에 주의해야 합니다. swapClass 메소드 안에서의 this는 jQuery 객체를 의미하고 .each() 메소드의 콜백함수에 사용된 this 키워드는 DOM 요소를 의미합니다. 이렇게 구현된 플러그-인은 DOM내의 모든 <div> 엘리먼트에 swapClass() 메소드를 적용합니다.

[메소드 체인]

앞에서’묵시적 반복’ 규칙을 준수한 예제11에서도 부족함이 보입니다. 이 플러그-인을 사용할 경우 선택자에 swapClass()를 적용한 후 다른 메소드를 적용하려면 다시 선택자에 해당 메소드를 호출하는 새로운 문장을 작성해야만 합니다. 그러나 예제1과 같이 일반적으로 jQuery 메소드는 메소드 체인을 사용하고 있습니다. 다른 메소드들과 함께 자요롭게 체인을 사용하게 되면 코드를 간결하게 만드는데에도 도움이 됩니다. 메소드 체인이 가능하도록 다음과 같은 규칙을 추가하겠습니다.

  • 특정한 값을 리턴할 의도가 없다면 선택 요소를 리턴한다

위의 규칙을 적용하여 메소드 체인을 사용할 수 있도록 수정하겠습니다. 그 결과는 예제12와 같습니다.

예제12

(function($) {
    $.fn.swapClass = function(class1, class2) {
        return this.each(function() {
            var $element = $(this);
            if ($element.hasClass(class1)) {
                $element.removeClass(class1).addClass(class2);
            }
            else if ($element.hasClass(class2)) {
                $element.removeClass(class2).addClass(class1);
            }
        });
    };
})(jQuery);

메소드 체인은 위와 같이 DOM요소를 리턴하는 것만으로도 간단히 구현됩니다. 묵시적 반복과 메소드 체인과 같은 규칙을 준수함으로서 기존 jQuery 메소들과의 일관성을 유지할 수 있고 플러그-인 개발자 외 다른 개발자들이 쉽게 이해하고 사용할 수 있습니다.

[파일명 짓기]

제작된 플러그-인을 파일로 저장시 파일이름 또한 다른 파일명과의 충돌을 고려해야 합니다. 아래 규칙은 jQuery팀에서 추천하는 명명규칙입니다.

접두어로 jQuery.를 사용한다. 이어서 플러그-인 이름을 적는다. 선택적으로 플러그-인의 메이저와 마이너 버전 값을 적는다. .js로 파일 이름을 끝맺는다. 제작된 플러그-인의 이름이 ‘nextree’라면 jquery.nextree-1.0.js 와 같은 파일명을 적용하면 되겠습니다.

마치며..

jQuery 플러그-인을 제작하는 것은 자바스크립트 일반 코드를 작성하는 것과 크게 다르지 않습니다. jQuery 환경의 자바스크립트 코딩에 익숙한 개발자라면 어려움없이 플러그-인을 제작할 것입니다. 자신뿐 아니라 동료 개발자들에게도 유용한 플러그-인을 개발한다면 개인의 발전을 넘어 프로젝트에 기여할 것입니다. 감사합니다.

php에서 mysql에서 가져온 값의 한글 깨짐현상 해결

  • 작업 조건
    • php
    • mysql
  • 작업 내용
    • php에서 mysql에서 가져온 Column의 값의 한글 깨짐 현상 해결
  • 작업 과정
    • 1. iconv() 사용하기
      • iconv(“현재 인코딩”, “바꿀 인코딩”, 바꿀 스트링)
      • $temp = iconv(‘utf8’, ‘euckr’, $temp);
    • 2. MySQL 입출력 incoding을 지정
      • 
        
  • 선택 사항
  • 작업 과정 중 참고사항
  • 작업 중 발생한 문제 해결
  • 작업과 관련된 주제
  • 참고 문헌

cafe24 bash에서 php 명령어 사용하기

  • 작업 조건
    • Unix type OS
    • installed php and dosen’t set bash command
  • 작업 내용
    • php 명령어를 Unix 계열 bash command로 사용하게 설정하기
  • 작업 과정
    • 1. php 가 설치되어 있는 지 확인하기
      • $ /usr/local/php55/bin/php –version
      • $ /usr/local/php/bin/php –version
    • 2. vi 편집기로 .bash_profile 편집
      • $ vi ~/.bash_profile
        • alias php=”/usr/local/php/bin/php”
  • 선택 사항
  • 작업 과정 중 참고사항
  • 작업 중 발생한 문제 해결
  • 작업과 관련된 주제
  • 참고 문헌

 

 

 

 

Laravel 5.4~5.5 다중 사용자인증

  • 작업 조건
    • PHP >= 5.6.4
    • OpenSSL PHP Extension
    • PDO PHP Extension
    • Mbstring PHP Extension
    • Tokenizer PHP Extension
    • XML PHP Extension
  • 작업 내용
    • Laravel 5.4에서 다중 사용자 인증 만들기
  • 작업 과정
    • 1. Laravel 5.4 project를 설치합니다.
      • composer create-project –prefer-dist laravel/laravel blog “5.4.*”
    • 2. admins migration table과 Model을 만듭니다.
      • &amp;amp;amp;amp;amp;amp;lt;?php
        use Illuminate\Support\Facades\Schema;
        use Illuminate\Database\Schema\Blueprint;
        use Illuminate\Database\Migrations\Migration;
        class CreateAdminsTable extends Migration
        {
         /**
         * Run the migrations.
         *
         * @return void
         */
         public function up()
         {
         Schema::create('admins', function (Blueprint $table) {
         $table-&amp;amp;amp;amp;amp;amp;gt;increments('id');
         $table-&amp;amp;amp;amp;amp;amp;gt;string('name');
         $table-&amp;amp;amp;amp;amp;amp;gt;string('email')-&amp;amp;amp;amp;amp;amp;gt;unique();
         $table-&amp;amp;amp;amp;amp;amp;gt;string('job_title');
         $table-&amp;amp;amp;amp;amp;amp;gt;string('password');
         $table-&amp;amp;amp;amp;amp;amp;gt;rememberToken();
         $table-&amp;amp;amp;amp;amp;amp;gt;timestamps();
         });
         }
         /**
         * Reverse the migrations.
         *
         * @return void
         */
         public function down()
         {
         Schema::dropIfExists('admins');
         }
        }
        
      • &amp;amp;amp;amp;amp;amp;lt;?php
        
        namespace App;
        
        use Illuminate\Notifications\Notifiable;
        use Illuminate\Foundation\Auth\User as Authenticatable;
        
        class Admin extends Authenticatable
        {
         use Notifiable;
        
         protected $guard = 'admin';
        
         /**
         * The attributes that are mass assignable.
         *
         * @var array
         */
         protected $fillable = [
         'name', 'email', 'password', 'job_title',
         ];
        
         /**
         * The attributes that should be hidden for arrays.
         *
         * @var array
         */
         protected $hidden = [
         'password', 'remember_token',
         ];
        }
        
      • 3. App/Exceiptions/Handler.php 에 다음 코드를 복사합니다.
        &amp;amp;amp;amp;amp;amp;lt;?php
        namespace App\Exceptions;
        use Exception;
        use Illuminate\Auth\AuthenticationException;
        use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
        class Handler extends ExceptionHandler
        {
         /**
         * A list of the exception types that should not be reported.
         *
         * @var array
         */
         protected $dontReport = [
         \Illuminate\Auth\AuthenticationException::class,
         \Illuminate\Auth\Access\AuthorizationException::class,
         \Symfony\Component\HttpKernel\Exception\HttpException::class,
         \Illuminate\Database\Eloquent\ModelNotFoundException::class,
         \Illuminate\Session\TokenMismatchException::class,
         \Illuminate\Validation\ValidationException::class,
         ];
         /**
         * Report or log an exception.
         *
         * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
         *
         * @param \Exception $exception
         * @return void
         */
         public function report(Exception $exception)
         {
         parent::report($exception);
         }
         /**
         * Render an exception into an HTTP response.
         *
         * @param \Illuminate\Http\Request $request
         * @param \Exception $exception
         * @return \Illuminate\Http\Response
         */
         public function render($request, Exception $exception)
         {
         return parent::render($request, $exception);
         }
         /**
         * Convert an authentication exception into an unauthenticated response.
         *
         * @param \Illuminate\Http\Request $request
         * @param \Illuminate\Auth\AuthenticationException $exception
         * @return \Illuminate\Http\Response
         */
         protected function unauthenticated($request, AuthenticationException $exception)
         {
         if ($request-&amp;amp;amp;amp;amp;amp;gt;expectsJson()) {
         return response()-&amp;amp;amp;amp;amp;amp;gt;json(['error' =&amp;amp;amp;amp;amp;amp;gt; 'Unauthenticated.'], 401);
         }
         $guard = array_get($exception-&amp;amp;amp;amp;amp;amp;gt;guards(), 0);
         switch ($guard) {
         case 'admin':
         $login = 'admin.login';
         break;
         default:
         $login = 'login';
         break;
         }
         return redirect()-&amp;amp;amp;amp;amp;amp;gt;guest(route($login));
         }
        }
        
      • 4. app/Http/Middleware/RedirectIfAuthenticated.php 으로 이동한 후 이 코드를 붙여넣습니다.
        &amp;amp;amp;amp;amp;lt;?php
        namespace App\Http\Middleware;
        use Closure;
        use Illuminate\Support\Facades\Auth;
        class RedirectIfAuthenticated
        {
         /**
         * Handle an incoming request.
         *
         * @param \Illuminate\Http\Request $request
         * @param \Closure $next
         * @param string|null $guard
         * @return mixed
         */
         public function handle($request, Closure $next, $guard = null)
         {
         switch ($guard) {
         case 'admin':
         if (Auth::guard($guard)-&amp;amp;amp;amp;amp;gt;check()) {
         return redirect()-&amp;amp;amp;amp;amp;gt;route('admin.dashboard');
         }
         break;
         default:
         if (Auth::guard($guard)-&amp;amp;amp;amp;amp;gt;check()) {
         return redirect('/home');
         }
         break;
         }
         return $next($request);
         }
        }
        
      • 5. Admin Controller를 만듭니다.
        &amp;amp;amp;amp;amp;lt;?php
        namespace App\Http\Controllers;
        use Illuminate\Http\Request;
        class AdminController extends Controller
        {
         /**
         * Create a new controller instance.
         *
         * @return void
         */
         public function __construct()
         {
         $this-&amp;amp;amp;amp;amp;gt;middleware('auth:admin');
         }
         /**
         * Show the application dashboard.
         *
         * @return \Illuminate\Http\Response
         */
         public function index()
         {
         return view('admin');
         }
        }
        
      • 6. 다음 명령어를 실행합니다. php artisan make:controller auth/AdminLoginController
      • 또는 AdminLoginController/Http/ Controllers/Auth/AdminLoginController.php를 생성하고 이 코드를 붙여넣습니다.
        &amp;amp;lt;?php
        namespace App\Http\Controllers\Auth;
        use Illuminate\Http\Request;
        use App\Http\Controllers\Controller;
        use Auth;
        class AdminLoginController extends Controller
        {
         public function __construct()
         {
         $this-&amp;amp;gt;middleware('guest:admin');
         }
         public function showLoginForm()
         {
         return view('auth.admin-login');
         }
         public function login(Request $request)
         {
         // Validate the form data
         $this-&amp;amp;gt;validate($request, [
         'email' =&amp;amp;gt; 'required|email',
         'password' =&amp;amp;gt; 'required|min:6'
         ]);
         // Attempt to log the user in
         if (Auth::guard('admin')-&amp;amp;gt;attempt(['email' =&amp;amp;gt; $request-&amp;amp;gt;email, 'password' =&amp;amp;gt; $request-&amp;amp;gt;password], $request-&amp;amp;gt;remember)) {
         // if successful, then redirect to their intended location
         return redirect()-&amp;amp;gt;intended(route('admin.dashboard'));
         }
         // if unsuccessful, then redirect back to the login with the form data
         return redirect()-&amp;amp;gt;back()-&amp;amp;gt;withInput($request-&amp;amp;gt;only('email', 'remember'));
         }
        }
        
      • 7. config/auth.php 파일에 이 코드를 붙여넣습니다.
        &amp;amp;lt;?php
        return [
         /*
         |--------------------------------------------------------------------------
         | Authentication Defaults
         |--------------------------------------------------------------------------
         |
         | This option controls the default authentication "guard" and password
         | reset options for your application. You may change these defaults
         | as required, but they're a perfect start for most applications.
         |
         */
         'defaults' =&amp;amp;gt; [
         'guard' =&amp;amp;gt; 'web',
         'passwords' =&amp;amp;gt; 'users',
         ],
         /*
         |--------------------------------------------------------------------------
         | Authentication Guards
         |--------------------------------------------------------------------------
         |
         | Next, you may define every authentication guard for your application.
         | Of course, a great default configuration has been defined for you
         | here which uses session storage and the Eloquent user provider.
         |
         | All authentication drivers have a user provider. This defines how the
         | users are actually retrieved out of your database or other storage
         | mechanisms used by this application to persist your user's data.
         |
         | Supported: "session", "token"
         |
         */
         'guards' =&amp;amp;gt; [
         'web' =&amp;amp;gt; [
         'driver' =&amp;amp;gt; 'session',
         'provider' =&amp;amp;gt; 'users',
         ],
         'api' =&amp;amp;gt; [
         'driver' =&amp;amp;gt; 'token',
         'provider' =&amp;amp;gt; 'users',
         ],
         'admin' =&amp;amp;gt; [
         'driver' =&amp;amp;gt; 'session',
         'provider' =&amp;amp;gt; 'admins',
         ],
         'admin-api' =&amp;amp;gt; [
         'driver' =&amp;amp;gt; 'token',
         'provider' =&amp;amp;gt; 'admins',
         ],
         ],
         /*
         |--------------------------------------------------------------------------
         | User Providers
         |--------------------------------------------------------------------------
         |
         | All authentication drivers have a user provider. This defines how the
         | users are actually retrieved out of your database or other storage
         | mechanisms used by this application to persist your user's data.
         |
         | If you have multiple user tables or models you may configure multiple
         | sources which represent each model / table. These sources may then
         | be assigned to any extra authentication guards you have defined.
         |
         | Supported: "database", "eloquent"
         |
         */
         'providers' =&amp;amp;gt; [
         'users' =&amp;amp;gt; [
         'driver' =&amp;amp;gt; 'eloquent',
         'model' =&amp;amp;gt; App\User::class,
         ],
         'admins' =&amp;amp;gt; [
         'driver' =&amp;amp;gt; 'eloquent',
         'model' =&amp;amp;gt; App\Admin::class,
         ],
         // 'users' =&amp;amp;gt; [
         // 'driver' =&amp;amp;gt; 'database',
         // 'table' =&amp;amp;gt; 'users',
         // ],
         ],
         /*
         |--------------------------------------------------------------------------
         | Resetting Passwords
         |--------------------------------------------------------------------------
         |
         | You may specify multiple password reset configurations if you have more
         | than one user table or model in the application and you want to have
         | separate password reset settings based on the specific user types.
         |
         | The expire time is the number of minutes that the reset token should be
         | considered valid. This security feature keeps tokens short-lived so
         | they have less time to be guessed. You may change this as needed.
         |
         */
         'passwords' =&amp;amp;gt; [
         'users' =&amp;amp;gt; [
         'provider' =&amp;amp;gt; 'users',
         'table' =&amp;amp;gt; 'password_resets',
         'expire' =&amp;amp;gt; 60,
         ],
         'admins' =&amp;amp;gt; [
         'provider' =&amp;amp;gt; 'admins',
         'table' =&amp;amp;gt; 'password_resets',
         'expire' =&amp;amp;gt; 15,
         ],
         ],
        ];
        
      • 8. Route file
        &amp;amp;lt;?php
        /*
        |--------------------------------------------------------------------------
        | Web Routes
        |--------------------------------------------------------------------------
        |
        | Here is where you can register web routes for your application. These
        | routes are loaded by the RouteServiceProvider within a group which
        | contains the "web" middleware group. Now create something great!
        |
        */
        Route::get('/', function () {
         return view('welcome');
        });
        Auth::routes();
        Route::get('/home', 'HomeController@index');
         Route::prefix('admin')-&amp;amp;gt;group(function() {
         Route::get('/login', 'Auth\AdminLoginController@showLoginForm')-&amp;amp;gt;name('admin.login');
         Route::post('/login', 'Auth\AdminLoginController@login')-&amp;amp;gt;name('admin.login.submit');
         Route::get('/', 'AdminController@index')-&amp;amp;gt;name('admin.dashboard');
         });
        
      • 9. admin.blade.php를 home.blade.php와 동일하게 만듭니다.
        @extends('layouts.app')
        
        @section('content')
        &lt;div class="container"&gt;
         &lt;div class="row"&gt;
         &lt;div class="col-md-8 col-md-offset-2"&gt;
         &lt;div class="panel panel-default"&gt;
         &lt;div class="panel-heading"&gt;ADMIN Dashboard&lt;/div&gt;
        
         &lt;div class="panel-body"&gt;
         You are logged in as &lt;strong&gt;ADMIN&lt;/strong&gt;
         &lt;/div&gt;
         &lt;/div&gt;
         &lt;/div&gt;
         &lt;/div&gt;
        &lt;/div&gt;
        @endsection
        

        10.views/auth/admin-login.blade.php를 만듭니다.

        @extends('layouts.app')
        
        @section('content')
        <div class="container">
        <div class="row">
        <div class="col-md-8 col-md-offset-2">
        <div class="panel panel-default">
        <div class="panel-heading">ADMIN Login</div>
        <div class="panel-body">
        
        {{ csrf_field() }}
        <div>has('email') ? ' has-error' : '' }}"&gt;
        E-Mail Address
        <div class="col-md-6">
        
        
        @if ($errors-&gt;has('email'))
        <span class="help-block">
        <strong>{{ $errors-&gt;first('email') }}</strong>
        </span>
        @endif
        </div>
        </div>
        <div>has('password') ? ' has-error' : '' }}"&gt;
        Password
        <div class="col-md-6">
        
        
        @if ($errors-&gt;has('password'))
        <span class="help-block">
        <strong>{{ $errors-&gt;first('password') }}</strong>
        </span>
        @endif
        </div>
        </div>
        <div class="form-group">
        <div class="col-md-6 col-md-offset-4">
        <div class="checkbox">
        
         Remember Me
        
        </div>
        </div>
        </div>
        <div class="form-group">
        <div class="col-md-8 col-md-offset-4">
        
        Login
        
        
        <a class="btn btn-link" href="{{ route('password.request') }}">
        Forgot Your Password?
        </a>
        </div>
        </div>
        
        </div>
        </div>
        </div>
        </div>
        </div>
        @endsection
        
  • 작업 중 참고사항
  • 작업 중 발생한 문제 해결
  • 작업과 관련된 주제
  • 참고 문헌