WeChat에 나만의 서비스 만들기 첫걸음

최근 중국내 서비스 개발하면서 WeChat과 연동해야 하는 부분이 생겨 WeChat OAuth 관련 기능을 개발하였습니다. WeChat은 한국에서는 채팅 서비스로 많이 알려져 있는데 실제 중국에서는 하나의 통합 모바일 플랫폼으로 사용되고 있습니다. 이 부분은 나중에 종합적으로 한번 소개하는 글을 작성하도록 하겠습니다.

이번에 작업한 내용은 WeChat의 공식 계정(Official Account, 公从号)와 관련된 기능입니다. WeChat을 모바일 플랫폼으로 만드는 것은 여러가지 기능이 있는데 그 중 공식 계정(Official Account, 公从号)이 대표적인 기능이라 할 수 있습니다. 공식 계정은 페이스북의 페이지와 비슷한 개념으로 기업이 WeChat 사용자를 대상으로 어떤 기능을 서비스하고 싶을 때 자신들의 기능을 만들어서 WeChat내에서 서비스를 할 수 있는 기능입니다. 많은 기업들이 이 공식 계정을 이용하고 있는데 다음 화면은 제가 방문했던 한 식당과 차이나 유니콤의 WeChat 공식 계정 서비스입니다.

china_unicom_official_account

페이스북의 페이지에는 Feed, 사진 등과 같이 페이스북에서 제공하는 컨텐츠만 등록할 수 있지만 WeChat의 공식 계정에는 이를 운영하는 회사가 자사의 모바일 웹을 운영할 수 있도록 하고 있습니다. 즉, 특별한 제약 없이 제공하고 싶은 모든 기능을 월 8억명 이상이 사용하는 WeChat 사용자에게 제공할 수 있도록 하고 있습니다. 이번 글에서는 이 공식 계정을 사용하는데 있어 가장 기본이 되는 사용자 인증에 대해 알아 보겠습니다.

WeChat 공식 계정 흐름

OAuth를 이해하기 전에 먼저 WeChat의 공식 계정이 어떻게 동작하는지에 대해 이해할 필요가 있는데 다음과 같은 흐름으로 처리 됩니다.

wechat_official_account_flow

사용자는 자신이 이미 Follow 하고 있는 기업 서비스 또는 검색을 통해 나타난 목록에서 해당 서비스를 클릭하면 WeChat 해당 계정에 등록된 URL을 호출해줍니다. 이 계정은 WeChat의 계정 관리 기능을 통해 등록, 수정이 가능합니다.

처음 요청 받은 페이지는 WeChat 내에 보여질 화면을 전달하면 WeChat 내에 내장된 브라우저에 보여지게 되고 이때 부터 사용자는 위챗 앱 안이지만 다른 서비스를 사용하게 되는 것입니다. 이렇게 위챗 내부에 있기 때문에 사용자 가입을 쉽게 받을 수 있고 이미 가입된 사용자의 경우 별도의 로그인 버튼없이 기업 계정을 클릭하는 것만으로 바로 로그인 처리를 할 수 있어 서비스 제공자 입장에서는 다양한 기능을 로그인된 사용자에게 제공할 수 있는 장점이 있습니다.

많은 공식 계정 서비스들은 첫페이지는 소식이나 상품을 제공하는 Feed 형태로 노출하고 화면 하단에 있는 버튼 메뉴를 이용하여 사용자의 회원 가입이나 구매 내역 확인 등을 처리하고 있습니다. 화면 하단의 메뉴도 공식 계정 관리화면에서 설정이 가능하도록 되어 있습니다.

WeChat OAuth

별도 로그인 없는 서비스를 제공하는 경우 HTML만으로도 WeChat내에 사용자에게 기능을 제공할 수 있고 또 기존에 WeChat 외부에서 사용하던 자체 로그인 기능을 제공할 수 도 있습니다. 위에서 예제로 보여드린 차이나 유니콤의 기업 계정의 경우에도 WeChat OAuth 기능을 사용하지 않고 자체 인증 기능을 사용하고 있습니다. 자체 인증을 사용하게 되면  id/password를 다시 입력해야 하고 패스워드 분실 등 때문에 다시 재요청해야 하는 등 로그인 부담이 무척 크게 다가 옵니다. 이렇기 때문에 최근에 많은 서비스들이 OAuth 인증을 채택하고 있습니다.

WeChat OAuth는 패이스북과 같은 다른 SNS와 비슷합니다. 이미 다른 SNS의 OAuth 경험이 있는 개발자라면 문서만 보면 바로 적용이 가능하리라 생각합니다. WeChat의 OAtuh 관련 문서는 다음에 잘 설명되어 있습니다. 여러 문서들이 중국어로 많이 되어 있는데 이 문서는 다행히도 영어로 되어 있습니다.

WeChat내 기업 계정 서비스는 내장 브라우저 위에서 동작하는 것이기 때문에 일반 브라우저가 거의 동일한 개념으로 이해하시면 됩니다. OAuth는 사용자가 인증을 필요한 링크를 클릭하게 되면 이를 받는 서버쪽 코드에서는 다음과 같이 OAuth 인증을 받은 후 결과를 받게 되는 Redirect URL을 담아서 WeChat 내장 브라우저로 Http Response에 302 Redirect로 보냅니다.

1
2
3
4
5
6
7
def wechat_oauth
  scope = 'snsapi_base'
  callback_url = "http://www.popit.kr/wechat/callback"
  app_id = "app1234"  //WeChat 관리 화면에서 가져옴
  wechat_authorize_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=&redirect_uri=#{callback_url}&response_type=code&scope=#{scope}&state=1#wechat_redirect"
  redirect_to wechat_authorize_url, status: 302
end

위 코드에서 중요한 인자는 callback_url과  scope입니다. callback_url은 WeChat에서 인증을 처리한 후 결과를 전달 받을 URL을 지정해줍니다. 즉, 우리 서비스의 URL을 적어 주면 됩니다. 예제의 경우 "/wechat/callback" 을 사용했는데 이 URL은 아래 설명할 코드에서 wechat_callback action에 대한 URL 입니다.

중요한 파라미터 중 남은 하나는 scope인데 scope에는 다음 두가지 중 하나를 사용할 수 있습니다.

  • snsapi_base: 단순히 해당 App에 대한 사용자의 Uniq한 ID(OpenID)를 가져오는데 사용
  • snsapi_userinfo: 성별, nickname, 사진, OpenID 등과 같이 사용자가 허용한 정보를 가져오는데 사용

state에는 WeChat이 인증을 거친 후 해당 서비스의 Redirect URL을 호출해 줄 때 이 파라미터를 그대로 전달하는데 각 서비스 입장에서 유효한 요청인지 등을 확인하는 용도로 사용할 수 있을 것 같습니다. 문서상에서는 랜덤 값을 설정할 수도 있다고 되어 있어 활용 용도는 각 서비스가 알아서 하라는 의미인 듯합니다.

마지막으로 WeChat의 authorize API 를 호출하는 URL을 302 Redirect로 다시 WeChat 내장 브라우저로 던달합니다.  302 Redirect로 전달된 URL을 받은 위챗 내장 브라우저는 scope이 snsapi_userinfo 로 된 경우 다음과 같이 사용자에게 인증을 확인하는 화면을 보여줍니다.

wechat_app_login

snsapi_base 경우에는 위 화면 없이 바로 다음 단계 진행으로 넘어가는데 snsapi_userinfo scope을 사용해도 가져올 수 있는 정보가 몇가지 없기 때문에 대부분은 snsapi_base 사용하고 있는 것 같습니다. 위 화면에서 사용자가 인증 확인을 하면(snsapi_base 인 경우 바로)  WeChat 내장 브라우저는 현재WeChat 에 로그인 사용자 정보를 확인할 수 있는 정보를 포함하여  "https://open.weixin.qq.com/connect/oauth2/authorize" 로 전달합니다. 그리고 다시 결과로 callback_url로 되어 있는(파라미터명 redirect_url)을 호출하면서 다음과 같은 형태로 호출합니다.

  • redirect_url/?code=CODE&state=STATE

사용자가 인증을 하지 않으면 code 파라미터가 없이 다음가 같이 호출됩니다.

  • redirect_url/?state=STATE

위 두가지 상황에서 알 수 있듯이 WeChat은 인증된 사용자의 정보를 확인할 수 있는 정보를 code 파라미터로 전달해 줍니다. 이 파라미터가 없으면 사용자의 인증 정보를 가져올 수 없습니다. 앞의 단계에서 사용자가 인증을 승인 했을 때 이를 받은 redirect_url에서는 다음과 같은 코드를 작성하여 사용자의 OpenID 또는 상세 정보를 가져올 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# GET /wechat/callback
def wechat_callback
  app_id = "app1234"  //WeChat 관리 화면에 있음
  secret_key = "1234567890"  //WeChat 관리 화면에 있음 
  code = params[:code]
  state = params[:state]
  access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=#{app_id&secret}=#{secret_key}&code=#{code}&grant_type=authorization_code"
  response = Utils::HttpRequestHandler.send_request(access_token_url, 'GET')
  raise "[WeChatCallback] Received error from WeChat while getting access_toke: #{response.code}" unless response.code.to_s.start_with?('2')
  auth_result = JSON.parse(response.body).with_indifferent_access
  access_token = auth_result[:access_token]
  expires_in = auth_result[:expires_in]
  openid = auth_result[:openid]
  refresh_token = auth_result[:refresh_token]
  scope = auth_result[:scope]
  user = get_user(openid)
  init_user_session(user)
  redirect_to "/index"
end

위 코드에서 보는 것처럼 code 파라미터 값을 이용하여 다시 access token을 가져오기 위해 WeChat API(https://api.weixin.qq.com/sns/oauth2/access_token)를 호출합니다. 이때 해당 서비스의 AppID와 Secret key를 전달하게 됩니다. access_token 요청으로 받은 결과의 body에 json 형태로 다음과 같은 정보가 있습니다.

  • access_token: 사용자 상세 정보를 조회하기 위해 필요한 token
  • expires_in: token의 만료 기간
  • openid: 이 App에서의 사용자의 uniq한 ID. 이 정보를 이용하여 공식 계정 서비스에서는 해당 사용자를 식별할 수 있음
  • refresh_token: ?
  • scope: 파라미터로 전달한 scope

인증만 필요한 상황에서는(scope=snsapi_base) 이렇게 사용자 정보를 받은 후 위 코드에서와 같이 서비스 내에서의 사용자 인증 처리를 해주면 됩니다.추가로 WeChat의 사용자 정보를 가져와야 하는 경우(scope=snsapi_userinfo) 위에서 받은 access_token을 이용하여 다시 한번 userinfo를 가져오기 위한 API를 호출합니다.

  • https://api.wechat.com/sns/userinfo?access_token=#{access_token}

서비스내에서 WeChat과 연동된 인증을 처리하기 위해서는 최초 사용자 가입 시 위 결과로 전달된 openid 정보를 사용자의 Uniq한 ID로 사용하여 관리해야 다음 로그인 시 해당 사용자인지 판별할 수 있게 됩니다.

지금까지 설명 전체 흐름을 정리하면 다음과 같습니다.

wechat_oauth_process

글을 마치며

이번 글에서는 매월 8억명 이상이 사용하는 WeChat에 자신만의 서비스를 올릴 수 있는 공식 계정에 대해 간단한 개념을 살펴 보았고 이 공식 계정 운영에 있어 반드시 필요한 OAuth 인증에 대해 알아 보았습니다.저도 중국에서 직접 이런 서비스를 개발해보기 전까지는 WeChat이 카카오톡이나 Line 과 같은 다른 채팅 서비스와의 플랫폼으로서 차별점을 잘 인식 못하고 있었는데 실제 개발을 해보니 아! 이래서 WeChat을 다른 메신저 서비스와는 다른 관점으로 이야기들 하는 구나 하는 생각을 가지게 되었습니다. 이번 글에서는 설명드리지 않는 기업 계정(企业号)의 기능을 알고 더욱 놀라게 되었습니다. 기업 계정에 대해서도 언제 기회가 되면 소개하도록 하겠습니다.

그리고 이 글에 앞서 WeChat 내에 공식 계정을 신청하는 것부터 설명하는 것이 더 좋았을 것 같은데 WeChat의 경우 다른 SNS 서비스와 다르게 공식 계정을 신청하는 부분이 간단하지 않습니다. 개발적인 부분보다는 거의 문서로 준비해야 하는 상황이라 이 부분에 대한 설명은 진행하지 않았습니다.

추가 그림

아래 질문에 대한 그림입니다. Callback URL은 다음 메뉴, 항목에서 등록합니다.

wechat_callback


Popit은 페이스북 댓글만 사용하고 있습니다. 페이스북 로그인 후 글을 보시면 댓글이 나타납니다.