oops-OAUTH2
[ class tree: oops-OAUTH2 ] [ index: oops-OAUTH2 ] [ all elements ]

Source for file NAVER.php

Documentation is available at NAVER.php

  1. <?php
  2. /**
  3.  * Project: oops\OAUTH2\NAVER :: 네이버 로그인(oauth2) pear package<br>
  4.  * File:    NAVER.php<br>
  5.  * Dependency:
  6.  *   - {@link http://pear.oops.org/docs/li_HTTPRelay.html oops/HTTPRelay}
  7.  *   - {@link http://pear.oops.org/docs/li_myException.html oops/myException}
  8.  *
  9.  * oops\OAUTH2\NAVER pear package는
  10.  * {@link http://developer.naver.com/wiki/pages/NaverLogin 네이버 아이디로 로그인}
  11.  * 을 pear package로 구현을 한 것이다.
  12.  *
  13.  * {@link http://developer.naver.com/wiki/pages/NaverLogin 네이버 아이디로 로그인}
  14.  * {@link http://developer.naver.com/wiki/pages/OAuth2 네이버 OAuth}와는 다른 API로서
  15.  * 로그인 사용자의 개인 식별 정보를 활용할 수 있으며, OAuth2 방식으로
  16.  * 구현이 되어있다.
  17.  *
  18.  * 이 package를 사용하기 위해서는 먼저 Naver에서 Application ID와 Application
  19.  * Secret을 발급받아야 한다. http://developer.naver.com/wiki/pages/NaverLogin 를
  20.  * 참고하라.
  21.  *
  22.  *
  23.  * @category  HTTP
  24.  * @package   oops\OAUTH2
  25.  * @subpackage oops\OAUTH2\NAVER
  26.  * @author    JoungKyun.Kim <http://oops.org>
  27.  * @copyright (c) 2019, OOPS.org
  28.  * @license   BSD License
  29.  * @example   OAUTH2/tests/naver.php NAVER pear package 예제 코드
  30.  * @filesource
  31.  */
  32.  
  33. namespace oops\OAUTH2;
  34.  
  35. /**
  36.  * import HTTPRelay class
  37.  */
  38. require_once 'HTTPRelay.php';
  39.  
  40.  
  41. /**
  42.  * Naver pear pcakge의 main class
  43.  *
  44.  * OAuth2를 이용하여 네이버 로그인을 진행하고, 로그인된 사용자의
  45.  * 정보를 얻어온다.
  46.  *
  47.  * @package oops\OAUTH2
  48.  * @subpackage oops\OAUTH2\NAVER
  49.  * @author    JoungKyun.Kim <http://oops.org>
  50.  * @copyright (c) 2019, OOPS.org
  51.  * @license   BSD License
  52.  * @example   OAUTH2/tests/naver.php NAVER pear 예제 코드
  53.  */
  54. Class NAVER {
  55.     // {{{ properities
  56.     /**#@+
  57.      * @access private
  58.      */
  59.     /**
  60.      * 세션 이름
  61.      * @var string 
  62.      */
  63.     private $sessid   '_OAUTH2_';
  64.     /**
  65.      * login url
  66.      * @var string 
  67.      */
  68.     private $reqAuth  'https://nid.naver.com/oauth2.0/authorize';
  69.     /**
  70.      * token url
  71.      * @var string 
  72.      */
  73.     private $reqToken 'https://nid.naver.com/oauth2.0/token';
  74.     /**
  75.      * user information url
  76.      * @var string 
  77.      */
  78.     private $reqUser  'https://apis.naver.com/nidlogin/nid/getUserProfile.xml';
  79.     /**
  80.      * revoke url
  81.      * @var string 
  82.      */
  83.     private $reqRevoke 'https://nid.naver.com/nidlogin.logout';
  84.     /**
  85.      * consumer information
  86.      * @var stdClass memebr는 다음과 같음
  87.      *    - id     : Naver login CliendID key
  88.      *    - secret : Naver login ClientSecret key
  89.      *    - callback : 이 class를 호출하는 페이지
  90.      */
  91.     private $consumer;
  92.     /**
  93.      * SSL type
  94.      * @var string 
  95.      */
  96.     private $proto 'http';
  97.     /**#@-*/
  98.     /**
  99.      * 네이버 로그인에 필요한 session 값
  100.      * @access public
  101.      * @var stdClass 
  102.      */
  103.     public $sess;
  104.     // }}}
  105.  
  106.     // {{{ +-- public (void) __construct ($v)
  107.     /**
  108.      * Naver 로그인 인증 과정을 수행한다. 인증 과정 중에
  109.      * 에러가 발생하면 myException 으로 에러 메시지를
  110.      * 보낸다.
  111.      *
  112.      * logout 시에 globale 변수 $_OAUTH2_LOGOUT_TEMPALTE_ 로 사용자 logout template
  113.      * 을 지정할 수 있다. template 파일은 pear/OAUTH2/login.template 를 참조하면 된다.
  114.      *
  115.      * @access public
  116.      * @param stdClass $v 
  117.      *    - id       발급받은 Naver login ClientID key
  118.      *    - secret   발급받은 Naver login ClientScret key
  119.      *    - callback 이 클래스가 호출되는 url
  120.      * @return void 
  121.      */
  122.     function __construct ($v{
  123.         if isset ($_SESSION[$this->sessid]) ) {
  124.             $_SESSION[$this->sessidnew \stdClass;
  125.             $_SESSION[$this->sessid]->appId = (object) $v;
  126.         }
  127.         $this->sess = &$_SESSION[$this->sessid];
  128.         $this->consumer = (object) $v;
  129.  
  130.         if isset ($_SERVER['HTTPS']) )
  131.             $this->proto .= 's';
  132.  
  133.         if isset ($_GET['logout']) ) {
  134.             $this->reqLogout ();
  135.             return;
  136.         }
  137.  
  138.         $this->checkError ();
  139.         $this->reqLogin ();
  140.         $this->reqAccessToken ();
  141.     }
  142.     // }}}
  143.  
  144.     // {{{ +-- private (string) mkToken (void)
  145.     /**
  146.      * 세션 유지를 위한 token 값
  147.      *
  148.      * @access private
  149.      * @return string 
  150.      */
  151.     private function mkToken ({
  152.         $mt microtime ();
  153.         $rand mt_rand ();
  154.         return md5 ($mt $rand);
  155.     }
  156.     // }}}
  157.  
  158.     // {{{ +-- private (void) reqLogin (void)
  159.     /**
  160.      * 로그인 창으로 redirect
  161.      *
  162.      * @access private
  163.      * @return void 
  164.      */
  165.     private function reqLogin ({
  166.         $cons &$this->consumer;
  167.         $this->sess->state $this->mkToken ();
  168.  
  169.         if $_GET['code'|| isset ($this->sess->oauth)  )
  170.             return;
  171.  
  172.         $url sprintf (
  173.             '%s?client_id=%s&response_type=code&redirect_uri=%s&state=%s',
  174.             $this->reqAuth$cons->idrawurlencode ($cons->callback),
  175.             $this->sess->state
  176.         );
  177.  
  178.         Header ('Location: ' $url);
  179.         exit;
  180.     }
  181.     // }}}
  182.  
  183.     // {{{ +-- private (void) reqAccessToken (void)
  184.     /**
  185.      * Authorization code를 발급받아 session에 등록
  186.      *
  187.      * NAVER::$sess->oauth 를 stdClass로 생성하고 다음의
  188.      * member를 등록한다.
  189.      *
  190.      *   - access_token:      발급받은 access token. expires_in(초) 이후 만료
  191.      *   - refresh_token:     access token 만료시 재발급 키 (14일 expire)
  192.      *   - token_type:        Bearer or MAC
  193.      *   - expires_in:        access token 유효시간(초)
  194.      *   - error:             error code
  195.      *   - error_description: error 상세값
  196.      *
  197.      * @access private
  198.      * @return void 
  199.      */
  200.     private function reqAccessToken ({
  201.         $sess &$this->sess;
  202.         $cons &$this->consumer;
  203.  
  204.         if $_GET['code'|| isset ($sess->oauth) )
  205.             return;
  206.  
  207.         $url sprintf (
  208.             '%s?client_id=%s&client_secret=%s&grant_type=authorization_code&state=%s&code=%s',
  209.             $this->reqToken$cons->id$cons->secret$sess->state$_GET['code']
  210.         );
  211.  
  212.         $http new \HTTPRelay;
  213.         $buf $http->fetch ($url);
  214.         $r json_decode ($buf);
  215.  
  216.         if $r->error )
  217.             $this->error ($r->error_description);
  218.         
  219.         $sess->oauth = (object) $r;
  220.     }
  221.     // }}}
  222.  
  223.     // {{{ +-- private (void) checkError (void)
  224.     /**
  225.      * 에러 코드가 존재하면 에러 처리를 한다.
  226.      *
  227.      * @access private
  228.      * @return void 
  229.      */
  230.     private function checkError ({
  231.         $sess &$this->sess;
  232.  
  233.         if $_GET['error')
  234.             $this->error ($_GET['error_description']);
  235.  
  236.         if $_GET['state'&& $_GET['state'!= $sess->state )
  237.             $this->error ('Invalude Session state: ' $_GET['state']);
  238.     }
  239.     // }}}
  240.  
  241.     // {{{ +-- private (void) error ($msg)
  242.     /**
  243.      * 에러를 Exception 처리한다.
  244.      *
  245.      * @access private
  246.      * @return void 
  247.      */
  248.     private function error ($msg{
  249.         $msg $_SERVER['HTTP_REFERER'"\n" $msg;
  250.         throw new \myException ($msgE_USER_ERROR);
  251.     }
  252.     // }}}
  253.  
  254.     // {{{ +-- private (string) redirectSelf (void)
  255.     /**
  256.      * 현재 URL에 after argument를 set한다.
  257.      *
  258.      * @access private
  259.      * @return string 
  260.      */
  261.     private function redirectSelf ({
  262.         if trim ($_SERVER['QUERY_STRING']) )
  263.             $qs sprintf ('?%s&after'$_SERVER['QUERY_STRING']);
  264.         else
  265.             $qs '?after';
  266.  
  267.         $req preg_replace ('/\?.*/'''trim ($_SERVER['REQUEST_URI']));
  268.         if $req $req '/';
  269.  
  270.         return sprintf (
  271.             '%s://%s%s%s',
  272.             $this->proto$_SERVER['HTTP_HOST']$req$qs
  273.         );
  274.     }
  275.     // }}}
  276.  
  277.     // {{{ +-- public (stdClass) Profile (void)
  278.     /**
  279.      * 로그인 과정이 완료되면 발급받은 NAVER::$sess->oauth 에 등록된
  280.      * 키를 이용하여 로그인 사용자의 정보를 가져온다.
  281.      *
  282.      * 2018-01-30 이후, 사용자 UID 만 기본 값이고, 나머지는 옵션으로 변경이 되어,
  283.      * 값이 없을 수 있다.
  284.      *
  285.      * @access public
  286.      * @return stdClass 다음의 object를 반환
  287.      *    - id       사용자 UID
  288.      *    - nickname 사용자 별칠
  289.      *    - realname 사용자 실명
  290.      *    - name     사용자 이름 (또는 사용자 별칭)
  291.      *    - email    이메일
  292.      *    - gender   성별
  293.      *    - age      나이대
  294.      *    - birth    출생년을 제외한 생일
  295.      *    - img      프로필 사진 URL 정보
  296.      */
  297.     public function Profile ({
  298.         $sess &$this->sess;
  299.  
  300.         if isset ($sess->oauth) )
  301.             return false;
  302.  
  303.         $req $sess->oauth->token_type ' ' $sess->oauth->access_token;
  304.  
  305.         $header array ('Authorization' => $req);
  306.         $http new \HTTPRelay ($header);
  307.         $buf $http->fetch ($this->reqUser);
  308.  
  309.         if $buf )
  310.             $this->error (sprintf ('[OAUTH2] Failed get user profile for %s'__CLASS__));
  311.  
  312.         $xml simplexml_load_string ($buf);
  313.         if $xml->result->resultcode != '00' )
  314.             $this->error ($r->result->message);
  315.  
  316.         $xmlr &$xml->response;
  317.  
  318.         $rname = (string) $xmlr->name{0};
  319.         $nname = (string) $xmlr->nickname{0};
  320.         $name $rname $rname $nname;
  321.  
  322.         $r array (
  323.             'id'       => (string) $xmlr->enc_id{0},
  324.             'realname' => $rname,
  325.             'nickname' => $nname,
  326.             'name'     => $name,
  327.             'email'    => (string) $xmlr->email{0},
  328.             'gender'   => (string) $xmlr->gender{0},
  329.             'age'      => (string) $xmlr->age{0},
  330.             'birth'    => (string) $xmlr->birthday,
  331.             'img'      => (string) $xmlr->profile_image
  332.         );
  333.  
  334.         return (object) $r;
  335.     }
  336.     // }}}
  337.  
  338.     // {{{ +-- public (void) reqLogout (void)
  339.     /**
  340.      * 네이버 로그인의 authorization key를 만료 시키고
  341.      * 세션에 등록된 정보(oops\OAUTH2\NAVER::$sess)를 제거한다.
  342.      *
  343.      * @access public
  344.      * @return void 
  345.      */
  346.     public function reqLogout ({
  347.         $sess &$this->sess;
  348.         $cons &$this->consumer;
  349.  
  350.         if isset ($sess->oauth) )
  351.             return;
  352.  
  353.         if isset ($_GET['after']) ) {
  354.             $url sprintf (
  355.                 '%s?grant_type=delete&client_id=%s&client_secret=%s&' .
  356.                 'access_token=%s&service_provider=NAVER',
  357.                 $this->reqToken$cons->id$cons->secret$sess->oauth->access_token
  358.             );
  359.  
  360.             $http new \HTTPRelay;
  361.             $buf $http->fetch ($url);
  362.  
  363.             $r json_decode ($buf);
  364.             if $r->error )
  365.                 $this->error ($r->error_description);
  366.  
  367.             unset ($_SESSION[$this->sessid]);
  368.  
  369.             if trim ($_SERVER['QUERY_STRING']) )
  370.                 $qs sprintf ('?%s&after'$_SERVER['QUERY_STRING']);
  371.             else
  372.                 $qs '?after';
  373.  
  374.             $redirect $_SERVER['SCRIPT_URI'$qs;
  375.  
  376.             $logoutDocPath 'OAUTH2/logout.template';
  377.             if $GLOBALS['_OAUTH2_LOGOUT_TEMPALTE_'{
  378.                 if file_exists ($GLOBALS['_OAUTH2_LOGOUT_TEMPALTE_']) )
  379.                     $logoutDocPath $GLOBALS['_OAUTH2_LOGOUT_TEMPALTE_'];
  380.             }
  381.             $logoutDoc file_get_contents ($logoutDocPathtrue);
  382.             $src array (
  383.                 '/{%VENDOR%}/',
  384.                 '/{%REDIRECT%}/',
  385.                 '/{%LOGOUT-URL%}/',
  386.                 '/{%WIN-WIDTH%}/',
  387.                 '/{%WIN-HEIGHT%}/',
  388.             );
  389.             $dst array (
  390.                 'NAVER',
  391.                 $redirect,
  392.                 $this->reqRevoke,
  393.                 600250
  394.             );
  395.             $logoutDoc preg_replace ($src$dst$logoutDoc);
  396.             echo $logoutDoc;
  397.             exit;
  398.         }
  399.     }
  400.     // }}}
  401. }
  402.  
  403. /*
  404.  * Local variables:
  405.  * tab-width: 4
  406.  * c-basic-offset: 4
  407.  * End:
  408.  * vim600: noet sw=4 ts=4 fdm=marker
  409.  * vim<600: noet sw=4 ts=4
  410.  */
  411. ?>

Documentation generated on Tue, 14 May 2019 02:00:40 +0900 by phpDocumentor 1.4.4