OpenID를 지원하기 위한 간단한 클래스

믹시(Mixi)의 OpenID지원(OpenID2.0만 지원한다)으로 인해서 인지는 몰라도
OpenID를 지원할 수 있도록 구축을 원하는 문의가 조금씩 있다고 한다.
한국에서는 상상이 안되는 시장을 가끔 일본에서 보게 되는데, 부럽기만하다.
(일본은 중소 솔루션 개발사들이 먹고 살 수 있는 환경이 만들어져 있다. 요즘은 조금 어렵지만서도...)

OpenID 라이브러리를 눈팅만 하다가 한번 만들어 봤는데 PHP를 이용했다.
(3년째 php를 하고 있지만 모르는 것 투성이다...-.- 그래도 웹어플리케이션 개발하기엔 참 편한 언어 중의 하나다.)

라이브러리에 대해서는 이곳 http://www.openidenabled.com/php-openid/을 참고하고 다운로드 받을 수 있다.
현재 OpenID가 1.1과 2.0 두 버젼으로 나뉘어 있는데, 가급적 2.0버젼을 받도록하자. 2.0버젼은 1.1도 지원해 주고 있다.
(라이브러리 다운로드 : php-openid-2.1.2.zip)

기본 로직들이야 라이브러리 안에 다 들어있으니 그걸 불러다 나만의 클래스를 만들어보자.
다운로드한 라이브러리를 적당한 위치에 풀어놓고 아래 클래스에서 라이브러리를 포함하기 위한 디렉토리를 수정한다.
참고로 OpenID인증 정보를 관리하기 위한 저장소로서 DB와 파일시스템이 있다.
이번 클래스는 간단히 파일시스템을 사용한다. DB를 이용하려면 관련된 추가 작업이 조금 필요하다.
파일 저장소를 지정할 때 리눅스 계열이라면 권한 설정(파일쓰기)에 조심한다.


<?php
$lib_path = dirname(__FILE__).'/'; // 여기에 라이브러리 디렉토리를 지정해 준다.
require_once($lib_path.'Auth/OpenID/Consumer.php');
require_once($lib_path.'Auth/OpenID/FileStore.php');
require_once($lib_path.'Auth/OpenID/SReg.php');

class OpenID {
    public  $id = '';
    public  $errorMessage = '';
    private $store_path = '';
    private $server_url = '';
    private $redirect_url = '';
    private $consumer = null;
    private $extensionKey = null;
    private $version = 2;
    private $extension = null;
   
    function debug($d) {
        global $lib_path;
        if (!file_exists($lib_path.'log')) mkdir($lib_path.'log');
        error_log('['.date("Y-m-d H:s:i").']'.$d."\r\n", 3, $lib_path.'log/openid.log');
    }
   
    /*
       $server : 이 클래스를 사용하는 URL
       $redirect : OpenID서버로부터 인증후에 결과를 받을 URL
   */
    function OpenID($server = '', $redirect = '') {
        global $lib_path;
       
        $this->debug('OpenID construct : '.$server.', redirect='.$redirect);
        $this->server_url = $server;
        $this->redirect_url = $redirect;
       
        // 파일 저장소로 사용할 디렉토리를 생성한다.
        $this->store_path = $lib_path.'tmp/openid';
        $this->debug('store path:'.$this->store_path);
        if (!file_exists($this->store_path)) @mkdir($this->store_path);
       
        // 파일저장소 생성
        $store = new Auth_OpenID_FileStore($this->store_path);
        // OpenID클라이언트 객체 생성
        $this->consumer = new Auth_OpenID_Consumer($store);
    }
   
    /*
       인증 결과를 처리하는 함수
       $addr : OpenID서버로부터 인증후에 결과를 받을 URL
   */
    function Finished($addr = '') {
        if($addr == '') $addr = $this->redirect_url;
        $response = $this->consumer->complete($addr);
        switch($response->status) {
            case Auth_OpenID_CANCEL:
                $this->errorMessage = 'Verification cancelled.';
                break;
            case Auth_OpenID_FAILURE:
                $this->errorMessage = 'OpenID authentication failed: '.$response->message;
                break;
            case Auth_OpenID_SUCCESS:
                $this->id = $response->getDisplayIdentifier();
               
                $sregResponse = Auth_OpenID_SRegResponse::FromSuccessResponse($response);
                $this->extension = $sregResponse->contents();
                $this->debug('Result:'.print_r($this->extension, true));
                break;
        }
        $this->debug('Finished : '.$addr);
        $this->debug('         Result : '.$response->status);
        if($response->status != Auth_OpenID_SUCCESS) $this->debug('         message : '.$response->message);
        return $response->status;
    }
   
    /*
       OpenID를 입력받아 해당 서버로 리다이렉트를 진행한다.
       $identifier : 사용자의 OpenID
    */
    function Login($identifier = '') {
        $result = '';
        if($identifier == '') {
            $this->errorMessage = "Authentication error; not a valid OpenID.";
            return false;
        }
        $req = $this->consumer->begin($identifier);
        if (!$req) {
            $this->errorMessage = "Authentication error; not a valid OpenID.";
            return false;
        }
       
        // 인증 후 추가 정보를 요청할 키를 생성한다.
        // 기본적으로 nickname or fullname, email을 요청하여 받는다.
        if($this->extensionKey == null)
            $sregRequest = Auth_OpenID_SRegRequest::build(
                                                array('nickname'),
                                                array('fullname', 'email') );
        else
            $sregRequest = Auth_OpenID_SRegRequest::build(array($this->extensionKey));
           
        if ($sregRequest) {
            $req->addExtension($sregRequest);
        }
       
        // 1.0과 2.0을 구분하여 처리한다.
        if($req->shouldSendRedirect()) {
            // OpenID 1.0
            $this->version = 1;
            $redirectUrl = $req->redirectURL(
                                    $this->server_url,
                                    $this->redirect_url );
           
            if(Auth_OpenID::isFailure($redirectUrl)) {
                $this->errorMessage = "Could not redirect to server: ".$redirectUrl;
                return false;
            } else {
                // 이용자의 OpenID에 해당하는 서버로 redirect
                $result = $redirectUrl;
                header("Location: ".$redirectUrl);
                exit();
            }
        } else {
            // OpenID 2.0
            $this->version = 2;
            $formHtml = $req->htmlMarkup($this->server_url,
                                        $this->redirect_url,
                                        false,
                                        array('id' => 'openid_message')
                                        );

            if (Auth_OpenID::isFailure($formHtml)) {
                $this->errorMessage = "Could not redirect to server: " . $formHtml->message;
                return false;
            } else {
                // 2.0관련하여 리다이렉트하기 위한 html을 작성하여 리다이렉트한다.
                $result =  $formHtml;
                echo($formHtml);
                exit();
            }       
        }
       
        return $result;
    }
   
    // 인증 후 추가 요청할 정보의 키를 설정
    function SetExtension($ar = null) {
        $this->extensionKey = $ar;
    }
   
    // 인증후 요청된 추가 정보 중에서 $key에 해당하는 값을 돌려준다.
    function GetExtension($key = '') {
        return $this->extension[$key];
    }
  
    // 현재 처리한 OpenID의 버젼을 돌려준다.
    function GetVersion() {
        return $this->version;
    }
}

?>

사용예

<?php
// 사용할 웹사이트 URL
define('LOGIN_SERVER', 'http://www.mimoweb.biz/openid/index.php');
// 인증후 돌아올 URL
define('REDIRECT_URL', 'http://www.mimoweb.biz/openid/index.php?action=finished');

session_start(); // 혹시나해서 세션을 시작했다. 자동 시작이면 필요 없다.
// 위의 클래스를 포함시킨다. 디렉토리 지정에 주의한다.
require_once('./class.openid.php');

// 객체 생성
$openid = new OpenID(LOGIN_SERVER, REDIRECT_URL);
$action = $_REQUEST['action'];
if($action == 'finished') {
    // 인증 후 결과를 처리한다.
    $ret = $openid->Finished(REDIRECT_URL);
} elseif($action == 'login') {
    $ret = '';
    $identifier = $_REQUEST['openid'];
    if(!isset($identifier) || $identifier == '')
        $identifier = 'http://mixi.jp'; // OpenID2.0 테스트로 일본의 믹시 사이트 지정

    $ret = $openid->Login($identifier);
}
?>
<html>
<head>
<title>OpenID test</title>
<style type="text/css">
img { border: 0px; }
</style>
</head>
<body>
<div>
<h1>Mixi OpenID2.0 test</h1>
Mixi<a href="?action=login">Mixi OpenID login</a>
</div>
<div>
<h1>OpenID test</h1>
<form action="" method="POST">
<input type="hidden" name="action" value="login" />
<input type="text" name="openid" value="" size="40" /><input type="submit" value=" Login " />
</form>
</div>
<div>Result</div>
<?php echo $ret; ?><br />
<p><pre>
<?php echo "your nickname: " . $openid->GetExtension('nickname') .PHP_EOL. "id: " . $openid->id; ?>
</pre></p>
<div > error : <?php echo $openid->errorMessage; ?> </div>

</body>
</html>
<?php
exit();
?>

의외로 간단하게 웹사이트에서 오픈아이디를 제공하여 많은 유저(?)를 모을 수 있다.
예제의 테스트는 http://www.mimoweb.biz/openid/index.php에서도 해 볼 수 있다.

한국에서도 많은 이용자를 확보하고 있는 회사들이 자발적으로 오픈아이디를 지원해 줬으면 좋겠다.

by 연서아빠 | 2008/09/11 11:44 | OpenID | 트랙백(2) | 덧글(2)

Tracked from 오픈소스 비즈니스 컨설팅 at 2008/09/19 15:44

제목 : 온라인 PC/서버 백업 서비스
저는 PC 데이터를 백업하기 위해서 두가지 방법을 사용하고 있습니다.첫째, EMC에서 무료로 제공하고 있는 온라인 PC 백업 서비스인 MozyHome를 사용합니다.단 2GB라는 용량 제한이 있어서 아주 중요한 데이터만 백업하고 있죠. 설정에 따라 다르지만 저는 매일 백업을 하고 있는데, 30일(30회)간 보관이 되어 문제가 발생하였을 때 쉽고 복원할 수 있어서 좋습니다.둘째, MS에서 무료로 제공하고 있는 폴더 동기화 프로그램인 SyncToy를......more

Tracked from 나에게 충고하기™ at 2009/01/21 11:16

제목 : 오픈아이디(OpenID) 적용프로젝트(표현이 거창함..
오픈아이디(OpenID)를 블로그에 적용해보려는 마음에 이곳저곳 자료를 찾아보고라이브러리들을 테스트해보려 하고있는데..궁극적인 문제를 해결하지 못하고는 더이상 진전을 볼 수가 없을 듯하다.대부분의 라이브러리들이 Curl을 이용하는 방식임에도 계정에서 Curl을 지원하지 않는다는 점 때문이다.혹시 Curl을 지원하지 않는 계정에서 오픈아이디 relying을 테스트 할수 있는 방법 아시는 분 도움 바랍니다. OpenID 란?Op......more

Commented by 산사랑 at 2008/09/11 14:36
와우! 참 간단하군요.

오픈 아이디라고 해서 어렵게만 생각했었는데. 저도 오픈 아이디를 사용하고 있는데 접속 정보를 공유하기에는 좋은 솔루션이더군요.
오픈소스로 Password Safe도 사용하고 있는데 이것은 오픈 아이디를 지원하지 않는 사이트를 위해 아이디와 암호를 저장해 두는 용도로 사용하고 있습니다. 저는 저의 대부분의 사이트, 서버, 은행, 증권 등에서 암호를 다 다르게 설정해서 사용하고 있어 저도 다 기억을 못 합니다. 그래서 Password Safe가 필요하죠.

Commented by 연서아빠 at 2008/09/11 15:22
저장하고 계신 자료를 백업하시는 것을 잊지 마세요. 가끔 PC가 고장나는 경우가 있거든요. ^.^;
※ 이 포스트는 더 이상 덧글을 남길 수 없습니다.

◀ 이전 페이지 다음 페이지 ▶