📜 ⬆️ ⬇️

Log in to VK for people

What happened?


Hello, dear reader. If you at least once worked with the Vkontakte API and at the same time write everything in python , probably the authorization of the application made you do several squats, after which you either don’t feel legs and faint, or you add quadriceps and still punch the API like Van Damm


For some reason, this seemingly unremarkable stage at first takes a huge amount of time and effort. My task: to help Habr's readers avoid leg injuries.


Next, I propose to consider a small library, which allows in one line to authorize your application for a specific user and get access_token . At the end of the article there is a link to the github repository of this library with quickstart in the README file.


Task


We want a small module that allows you to authorize beautifully, universally and as safely as possible, and which is very simple to use.
It is worth saying that this solution is an improvement and generalization of the variant proposed in this article.


So, we use python3.5 , a library for html requests and getpass requests for hidden password input.


Our task: several times contact the correct address, each time parsit <form> , send the answer and finally get the desired access_token .


Implementation


Let's start by creating a class. During initialization, we will require a list of "permissions" to which the application wants to access, the id of this application and the version of the VK API. Plus, add a few optional parameters, the value of each of which is clarified further.


__Init__ method
 class VKAuth(object): def __init__(self, permissions, app_id, api_v, email=None, pswd=None, two_factor_auth=False, security_code=None, auto_access=True): """ Args: permissions: list of Strings with permissions to get from API app_id: (String) vk app id that one can get from vk.com api_v: (String) vk API version """ self.session = requests.Session() self.form_parser = FormParser() self.user_id = None self.access_token = None self.response = None self.permissions = permissions self.api_v = api_v self.app_id = app_id self.two_factor_auth= two_factor_auth self.security_code = security_code self.email = email self.pswd = pswd self.auto_access = auto_access if security_code != None and two_factor_auth == False: raise RuntimeError('Security code provided for non-two-factor authorization') 

As mentioned in the article already mentioned, we need to skillfully roll cookies and redirectes. All this is done for us by the requests library with an object of the Session class. We’ll get this one in the field self.session . To parse the html document, the standard HTMLParser class from the html.parser module is html.parser . For the parser, a class ( FormParser ) is also written, which doesn't make much sense, since it almost completely repeats the one from the mentioned article. The only significant difference is that the one used here allows you to gracefully reject the authorization of the application at the last step, if you suddenly change your mind.


The user_id and access_token will be filled in after successful authorization, response stores the result of the last html request.


The library user will be provided with a single method - authorize , which performs 3 steps:


  1. application authorization request
  2. user authorization
    2.1 the introduction of key-code in the case of two-factor authentication
  3. confirmation of permission to use permissions

Lets go through each step.


Step 1. Request to authorize the application


Carefully compose the url of the request (you can read about the parameters here ), send the request and parse the resulting html.


The authorize method for Step 1
 def authorize(self): api_auth_url = 'https://oauth.vk.com/authorize' app_id = self.app_id permissions = self.permissions redirect_uri = 'https://oauth.vk.com/blank.html' display = 'wap' api_version = self.api_v auth_url_template = '{0}?client_id={1}&scope={2}&redirect_uri={3}&display={4}&v={5}&response_type=token' auth_url = auth_url_template.format(api_auth_url, app_id, ','.join(permissions), redirect_uri, display, api_version) self.response = self.session.get(auth_url) # look for <form> element in response html and parse it if not self._parse_form(): raise RuntimeError('No <form> element found. Please, check url address') 

Step 2. User authorization


The _log_in() and _two_fact_auth() methods are implemented for [not] successful authorization of a user in VK if he is not authorized (and he is not authorized). Both methods use the previously defined email , pswd , two_factor_auth and security_code fields. If some of the fields were not supplied with an argument when initializing an object of the VKAuth class, they will be asked to enter into the console, and in case of failure they will be asked to enter again. Two-factor authentication is optional and disabled by default, and our module notifies the user of its presence with an error.


The authorize method for Step 2 (continued from Step 1)
 #look for <form> element in response html and parse it if not self._parse_form(): raise RuntimeError('No <form> element found. Please, check url address') else: # try to log in with email and password (stored or expected to be entered) while not self._log_in(): pass; # handling two-factor authentication # expecting a security code to enter here if self.two_factor_auth: self._two_fact_auth() 

The _log_in method for Step 2
 def _log_in(self): if self.email == None: self.email = '' while self.email.strip() == '': self.email = input('Enter an email to log in: ') if self.pswd == None: self.pswd = '' while self.pswd.strip() == '': self.pswd = getpass.getpass('Enter the password: ') self._submit_form({'email': self.email, 'pass': self.pswd}) if not self._parse_form(): raise RuntimeError('No <form> element found. Please, check url address') # if wrong email or password if 'pass' in self.form_parser.params: print('Wrong email or password') self.email = None self.pswd = None return False elif 'code' in self.form_parser.params and not self.two_factor_auth: raise RuntimeError('Two-factor authentication expected from VK.\nChange `two_factor_auth` to `True` and provide a security code.') else: return True 

The _two_fact_auth method for Step 2
 def _two_fact_auth(self): prefix = 'https://m.vk.com' if prefix not in self.form_parser.url: self.form_parser.url = prefix + self.form_parser.url if self.security_code == None: self.security_code = input('Enter security code for two-factor authentication: ') self._submit_form({'code': self.security_code}) if not self._parse_form(): raise RuntimeError('No <form> element found. Please, check url address') 

Step 3. Confirming permissions and getting access_token


The hardest thing behind. Now it's up to you. We use our improvement of the form parser to find in the html document that has just arrived to us a button with the inscription "Allow" and pull out the authorization confirmation url from it. Nearby is the reject button - we will save its url. The auto_access field auto_access to True , so this confirmation should not make life difficult for us.


Finally, we save the received access_token and user_id from the url, which was transmitted after confirmation of authorization.


Now you can have fun using the VK API.


http: // REDIRECT_URI # access_token = 533bacf01e11f55b536a565b57531ad114461ae8736d6506a3 & expires_in = 86400 & user_id = 8492

The authorize method for Step 3
  # allow vk to use this app and access self.permissions self._allow_access() # now get access_token and user_id self._get_params() 

_Allow_access method for step 3
 def _allow_access(self): parser = self.form_parser if 'submit_allow_access' in parser.params and 'grant_access' in parser.url: if not self.auto_access: answer = '' msg = 'Application needs access to the following details in your profile:\n' + \ str(self.permissions) + '\n' + \ 'Allow it to use them? (yes or no)' attempts = 5 while answer not in ['yes', 'no'] and attempts > 0: answer = input(msg).lower().strip() attempts-=1 if answer == 'no' or attempts == 0: self.form_parser.url = self.form_parser.denial_url print('Access denied') self._submit_form({}) 

_Get_params method for step 3
  def _get_params(self): try: params = self.response.url.split('#')[1].split('&') self.access_token = params[0].split('=')[1] self.user_id = params[2].split('=')[1] except IndexError(e): print(e) print('Coudln\'t fetch token') 

github : VKAuth


Leave comments and reviews here and on github. Good luck on the battlefield, and take care of your feet.


')

Source: https://habr.com/ru/post/306022/


All Articles