oauthmanager.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. from abc import ABCMeta, abstractmethod, abstractproperty
  2. from oauth.models import OAuthUser, OAuthConfig
  3. from django.conf import settings
  4. import requests
  5. import json
  6. import logging
  7. import urllib.parse
  8. from website.utils import parse_dict_to_url
  9. logger = logging.getLogger(__name__)
  10. class BaseOauthManager(metaclass=ABCMeta):
  11. """获取用户授权"""
  12. AUTH_URL = None
  13. """获取token"""
  14. TOKEN_URL = None
  15. """获取用户信息"""
  16. API_URL = None
  17. '''icon图标名'''
  18. ICON_NAME = None
  19. def __init__(self, access_token=None, openid=None):
  20. self.access_token = access_token
  21. self.openid = openid
  22. @property
  23. def is_access_token_set(self):
  24. return self.access_token is not None
  25. @property
  26. def is_authorized(self):
  27. return self.is_access_token_set and self.access_token is not None and self.openid is not None
  28. @abstractmethod
  29. def get_authorization_url(self, nexturl='/'):
  30. pass
  31. @abstractmethod
  32. def get_access_token_by_code(self, code):
  33. pass
  34. @abstractmethod
  35. def get_oauth_userinfo(self):
  36. pass
  37. def do_get(self, url, params):
  38. rsp = requests.get(url=url, params=params)
  39. return rsp.text
  40. def do_post(self, url, params):
  41. rsp = requests.post(url, params)
  42. return rsp.text
  43. def get_config(self):
  44. value = OAuthConfig.objects.filter(type=self.ICON_NAME)
  45. return value[0] if value else None
  46. class WBOauthManager(BaseOauthManager):
  47. AUTH_URL = 'https://api.weibo.com/oauth2/authorize'
  48. TOKEN_URL = 'https://api.weibo.com/oauth2/access_token'
  49. API_URL = 'https://api.weibo.com/2/users/show.json'
  50. ICON_NAME = 'weibo'
  51. def __init__(self, access_token=None, openid=None):
  52. config = self.get_config()
  53. self.client_id = config.appkey if config else ''
  54. self.client_secret = config.appsecret if config else ''
  55. self.callback_url = config.callback_url if config else ''
  56. super(WBOauthManager, self).__init__(access_token=access_token, openid=openid)
  57. def get_authorization_url(self, nexturl='/'):
  58. params = {
  59. 'client_id': self.client_id,
  60. 'response_type': 'code',
  61. 'redirect_uri': self.callback_url + '&next_url=' + nexturl
  62. }
  63. url = self.AUTH_URL + "?" + urllib.parse.urlencode(params)
  64. return url
  65. def get_access_token_by_code(self, code):
  66. params = {
  67. 'client_id': self.client_id,
  68. 'client_secret': self.client_secret,
  69. 'grant_type': 'authorization_code',
  70. 'code': code,
  71. 'redirect_uri': self.callback_url
  72. }
  73. rsp = self.do_post(self.TOKEN_URL, params)
  74. try:
  75. obj = json.loads(rsp)
  76. self.access_token = str(obj['access_token'])
  77. self.openid = str(obj['uid'])
  78. return self.get_oauth_userinfo()
  79. except Exception as e:
  80. logger.error(e)
  81. return None
  82. def get_oauth_userinfo(self):
  83. if not self.is_authorized:
  84. return None
  85. params = {
  86. 'uid': self.openid,
  87. 'access_token': self.access_token
  88. }
  89. rsp = self.do_get(self.API_URL, params)
  90. try:
  91. datas = json.loads(rsp)
  92. user = OAuthUser()
  93. user.matedata = rsp
  94. user.picture = datas['avatar_large']
  95. user.nikename = datas['screen_name']
  96. user.openid = datas['id']
  97. user.type = 'weibo'
  98. user.token = self.access_token
  99. if 'email' in datas and datas['email']:
  100. user.email = datas['email']
  101. return user
  102. except Exception as e:
  103. logger.error(e)
  104. logger.error('weibo oauth error.rsp:' + rsp)
  105. return None
  106. class GoogleOauthManager(BaseOauthManager):
  107. AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth'
  108. TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token'
  109. API_URL = 'https://www.googleapis.com/oauth2/v3/userinfo'
  110. ICON_NAME = 'google'
  111. def __init__(self, access_token=None, openid=None):
  112. config = self.get_config()
  113. self.client_id = config.appkey if config else ''
  114. self.client_secret = config.appsecret if config else ''
  115. self.callback_url = config.callback_url if config else ''
  116. super(GoogleOauthManager, self).__init__(access_token=access_token, openid=openid)
  117. def get_authorization_url(self, nexturl='/'):
  118. params = {
  119. 'client_id': self.client_id,
  120. 'response_type': 'code',
  121. 'redirect_uri': self.callback_url,
  122. 'scope': 'openid email',
  123. }
  124. # url = self.AUTH_URL + "?" + urllib.parse.urlencode(params, quote_via=urllib.parse.quote)
  125. url = self.AUTH_URL + "?" + urllib.parse.urlencode(params)
  126. return url
  127. def get_access_token_by_code(self, code):
  128. params = {
  129. 'client_id': self.client_id,
  130. 'client_secret': self.client_secret,
  131. 'grant_type': 'authorization_code',
  132. 'code': code,
  133. 'redirect_uri': self.callback_url
  134. }
  135. rsp = self.do_post(self.TOKEN_URL, params)
  136. obj = json.loads(rsp)
  137. try:
  138. self.access_token = str(obj['access_token'])
  139. self.openid = str(obj['id_token'])
  140. logger.info(self.ICON_NAME + ' oauth ' + rsp)
  141. return self.access_token
  142. except Exception as e:
  143. logger.error(e)
  144. logger.error(self.ICON_NAME + ' oauth error ' + rsp)
  145. return None
  146. def get_oauth_userinfo(self):
  147. if not self.is_authorized:
  148. return None
  149. params = {
  150. 'access_token': self.access_token
  151. }
  152. rsp = self.do_get(self.API_URL, params)
  153. try:
  154. datas = json.loads(rsp)
  155. user = OAuthUser()
  156. user.matedata = rsp
  157. user.picture = datas['picture']
  158. user.nikename = datas['name']
  159. user.openid = datas['sub']
  160. user.token = self.access_token
  161. user.type = 'google'
  162. if datas['email']:
  163. user.email = datas['email']
  164. return user
  165. except Exception as e:
  166. logger.error(e)
  167. logger.error('google oauth error.rsp:' + rsp)
  168. return None
  169. class GitHubOauthManager(BaseOauthManager):
  170. AUTH_URL = 'https://github.com/login/oauth/authorize'
  171. TOKEN_URL = 'https://github.com/login/oauth/access_token'
  172. API_URL = 'https://api.github.com/user'
  173. ICON_NAME = 'github'
  174. def __init__(self, access_token=None, openid=None):
  175. config = self.get_config()
  176. self.client_id = config.appkey if config else ''
  177. self.client_secret = config.appsecret if config else ''
  178. self.callback_url = config.callback_url if config else ''
  179. super(GitHubOauthManager, self).__init__(access_token=access_token, openid=openid)
  180. def get_authorization_url(self, nexturl='/'):
  181. params = {
  182. 'client_id': self.client_id,
  183. 'response_type': 'code',
  184. 'redirect_uri': self.callback_url + '&next_url=' + nexturl,
  185. 'scope': 'user'
  186. }
  187. # url = self.AUTH_URL + "?" + urllib.parse.urlencode(params, quote_via=urllib.parse.quote)
  188. url = self.AUTH_URL + "?" + urllib.parse.urlencode(params)
  189. return url
  190. def get_access_token_by_code(self, code):
  191. params = {
  192. 'client_id': self.client_id,
  193. 'client_secret': self.client_secret,
  194. 'grant_type': 'authorization_code',
  195. 'code': code,
  196. 'redirect_uri': self.callback_url
  197. }
  198. rsp = self.do_post(self.TOKEN_URL, params)
  199. try:
  200. from urllib import parse
  201. r = parse.parse_qs(rsp)
  202. self.access_token = (r['access_token'][0])
  203. return self.access_token
  204. except Exception as e:
  205. logger.error(e)
  206. return None
  207. def get_oauth_userinfo(self):
  208. params = {
  209. 'access_token': self.access_token
  210. }
  211. rsp = self.do_get(self.API_URL, params)
  212. try:
  213. datas = json.loads(rsp)
  214. user = OAuthUser()
  215. user.picture = datas['avatar_url']
  216. user.nikename = datas['name']
  217. user.openid = datas['id']
  218. user.type = 'github'
  219. user.token = self.access_token
  220. user.matedata = rsp
  221. if datas['email']:
  222. user.email = datas['email']
  223. return user
  224. except Exception as e:
  225. logger.error(e)
  226. logger.error('github oauth error.rsp:' + rsp)
  227. return None
  228. class FaceBookOauthManager(BaseOauthManager):
  229. AUTH_URL = 'https://www.facebook.com/v2.10/dialog/oauth'
  230. TOKEN_URL = 'https://graph.facebook.com/v2.10/oauth/access_token'
  231. API_URL = 'https://graph.facebook.com/me'
  232. ICON_NAME = 'facebook'
  233. def __init__(self, access_token=None, openid=None):
  234. config = self.get_config()
  235. self.client_id = config.appkey if config else ''
  236. self.client_secret = config.appsecret if config else ''
  237. self.callback_url = config.callback_url if config else ''
  238. super(FaceBookOauthManager, self).__init__(access_token=access_token, openid=openid)
  239. def get_authorization_url(self, nexturl='/'):
  240. params = {
  241. 'client_id': self.client_id,
  242. 'response_type': 'code',
  243. 'redirect_uri': self.callback_url, # + '&next_url=' + nexturl,
  244. 'scope': 'email,public_profile'
  245. }
  246. url = self.AUTH_URL + "?" + urllib.parse.urlencode(params)
  247. return url
  248. def get_access_token_by_code(self, code):
  249. params = {
  250. 'client_id': self.client_id,
  251. 'client_secret': self.client_secret,
  252. # 'grant_type': 'authorization_code',
  253. 'code': code,
  254. 'redirect_uri': self.callback_url
  255. }
  256. rsp = self.do_post(self.TOKEN_URL, params)
  257. try:
  258. obj = json.loads(rsp)
  259. token = str(obj['access_token'])
  260. self.access_token = token
  261. return self.access_token
  262. except Exception as e:
  263. logger.error(e)
  264. return None
  265. def get_oauth_userinfo(self):
  266. params = {
  267. 'access_token': self.access_token,
  268. 'fields': 'id,name,picture,email'
  269. }
  270. try:
  271. rsp = self.do_get(self.API_URL, params)
  272. datas = json.loads(rsp)
  273. user = OAuthUser()
  274. user.nikename = datas['name']
  275. user.openid = datas['id']
  276. user.type = 'facebook'
  277. user.token = self.access_token
  278. user.matedata = rsp
  279. if datas['email']:
  280. user.email = datas['email']
  281. if datas['picture'] and datas['picture']['data'] and datas['picture']['data']['url']:
  282. user.picture = str(datas['picture']['data']['url'])
  283. return user
  284. except Exception as e:
  285. logger.error(e)
  286. return None
  287. def get_oauth_apps():
  288. configs = OAuthConfig.objects.filter(is_enable=True).all()
  289. if not configs:
  290. return []
  291. configtypes = [x.type for x in configs]
  292. applications = BaseOauthManager.__subclasses__()
  293. apps = [x() for x in applications if x().ICON_NAME.lower() in configtypes]
  294. return apps
  295. def get_manager_by_type(type):
  296. applications = get_oauth_apps()
  297. finds = list(filter(lambda x: x.ICON_NAME.lower() == type.lower(), applications))
  298. if finds:
  299. return finds[0]
  300. return None