Делаем mash-up приложение на трэндах

Разделы

Показаны сообщения с ярлыком oauth. Показать все сообщения
Показаны сообщения с ярлыком oauth. Показать все сообщения

понедельник, 13 августа 2012 г.

Знакомство с Facebook

Вообщем Фэйсбук не такой уж и страшный и с ним даже можно и нужно работать. А начал я своё знакомство с ним сразу с приложения. Приложение пишется очень быстро, но долго дорабатывается, т.к. удалось въехать совсем не с первого раза в механизмы авторизации и шаманство с куками - иначе это не назовёшь, т.к. приложение работает во фрейме.

Как я уже сказал приложение пишетс достаточно быстро - ровно столько же сколько происходило изучение доков, прежде чем приступить. И поэтому что бы обезопасить от набития шишек кое что расскажу из предварительных настроек. Как создаётся приложение?

Приложение начинается с этого адреса, в котором при его создании, самое сложное было в Basic - меню выбрать какой какой тип приложения я хочу использовать. Так как я делаю серверные приложения (пока ещё) то мой выбор пал на два: App on Facebook и Page Tab. И я долго долго ковырялся на просторах фэйсбука пока не нашёл (потерял) доходичвую документацию - что они отличаются тем, как будут встраиваться на страницу. В первом случае приложение будет работать в указанном канвасе, а со страницей пользователя общаться через апи, а во втором случае, после встраивания в таб приложение выдаёт индивидульную информацию прямо в таб, при этом поддерживается разные языки-макросы FBML, FQL, FBJS... Очевидно я остановился на приложение в канвасе которое общается через АПИ и чего-то там делает в стандартных фэйсбучных объектах - коих предостаточно.

Проблема номер два, устаревающая авторизация. Здесь я буду краток, хотя уже написав приложение пришлось его перелопачивать из-за ткой мелочи как short-time lived token. В новых версиях (новых потому что их две с сентября и октября 2012) откзались от оффлайн авторизации при этом предложили "длинный" токен, который можно получить через запрос сервера. Но он не обновляется! Обновлять можно только короткий токен, который получается на клиенте. Короче что бы приложение могло работать лайфтайм надо брать короткий токен при каждой новой возможности, и обновлять его на длинный. Кстати длинный живёт 60 дней короткий 24 часа. Примеры не выкладываю, т.к. есть отличный пример Run with Friends, написанный прямо на питоне и прямо для ГАЕ. Чуть критики: мне немного не понравилась его логика, но может я просто не привычный к Джанго, но пример сам по себе достаточно полный, включает все необходимое для того что бы начать писать под Facebook. На этом всё, и да кстати пользуйтесь приложением, если есть свои фанпаги - можно зарабатывать с Амазон в фэйсбуке. Удачи!

пятница, 29 июня 2012 г.

Amazon - партнёрский магазин

Вообщем, простое решение привело меня к Amazon. Вопрос стоял так: чем наполнять сайт, пока нет авторского материала, и не совсем прямым путём пришёл к Амазон. Конечно же брать оттуда контент как дополнительный не стоит, а стоит взять его за основной, а всё что удалось добыть иным путём разместить вместе с ним. Amazon он большой, поэтому здесь сейчас будет краткий обзор, скорей так сказать букмарки с коментами.

Итак с чего начать:
Партнёрская программа
Доступ к API
Полезные доки (из множетсва других)
И наконец песочница, поигратся с запросами

Ещё есть библиотека для питон, но не факт что она заработает в GAE - причём у неё вид страшноватый (огромное количество файлов непонято для чего). Имя всё это и принимая во внимание последнее, решил на написать свою библитеку доступа к их базе.
Сначала думал что убдет всё просто, но по факту что-то сразу не пошло, а загвоздка сводилась к тому что они импользуют какой что старый интерфейс OAuth, верней он у них свой, похож просто. Отличие в том сообщение формируют несколько иначе и подписывают не SHA1 а SHA256. Ниже код
#!/usr/bin/env python
# encoding: utf-8

from google.appengine.api import urlfetch
from urllib import quote, unquote, urlencode
from hmac import new as hmac
from hashlib import sha256
from datetime import datetime
from urlparse import urlparse


import logging
from settings import AMAZON_TAG, AMAZON_KEY, AMAZON_SECRET

try:
    import json
except ImportError:
    import simplejson as json

def amazon_request(url="", additional_params=None, method=urlfetch.GET):
    def _quote(text):
        return quote(str(text), "~")
    
    url = url if url else "http://ecs.amazonaws.com/onca/xml" 
    
    consumer_key = AMAZON_KEY
    consumer_secret = AMAZON_SECRET
    
    params = {"Service": "AWSECommerceService",
                        "AssociateTag": "AMAZON_TAG",
                        "AWSAccessKeyId": consumer_key,
                        "Timestamp": datetime.now().strftime("%Y-%m-%dT%H:%M:%S.000Z")
                        }

    if additional_params:
        params.update(additional_params)
    
    for k,v in params.items():
        if isinstance(v, unicode):
            params[k] = v.encode('utf8')

    params_str = "&".join(["%s=%s" % (_quote(k), _quote(params[k])) for k in sorted(params)])
    parse_url = urlparse(url)
    message = "\n".join(["GET" if method == urlfetch.GET else "POST", parse_url.netloc, parse_url.path, params_str])
    params["Signature"] = hmac(consumer_secret, message, sha256).digest().encode("base64").strip()

    payload = urlencode(params)

    if method == urlfetch.GET:
        url = "%s?%s" % (url, payload)
        payload = None

    rpc = urlfetch.create_rpc(deadline=12.0)
    urlfetch.make_fetch_call(rpc, url, method=method, payload=payload)
    
    try:
        res = rpc.get_result()
    except urlfetch.DownloadError, msg:
        logging.error(msg)
        logging.error(repr(additional_params))
        return None

    if res.status_code != 200:
        logging.error("amazon_request: status_code")
        logging.error(repr(additional_params))
        if res.content:
            logging.error(res.content)
            logging.error("token is %s" % token)
        return None
    
    return res.content
P.S.: Если прокатит одна штука, будет статейка про блоггер - уж очень мне их новый дизайн приглянулся, к тому же не надо забывать что это хостинг и притом бесплатный.

воскресенье, 29 мая 2011 г.

OAuth для твиттера (продолжение)

Буду краток. Вчера времени не хватило, не успел выход сделать:
@route('/exit')
@route('/exit/')
def exit_view():
    del_cookie()
    redirect("/")
И кстати заодно файлик для работы с куками:
Листинг cookie.py:
@route('/login')
#!/usr/bin/env python
# encoding: utf-8

from bottle import route, run, view, request, redirect, response, post, abort, debug, error
import logging
import hmac
import uuid
import base64
from google.appengine.ext import db
from datetime import datetime
from datetime import timedelta

from models import Users
from oauth import TwitterClient


def generate_rnd_hash(uid):
    h = hmac.new(str(uid))
    h.update(uuid.uuid4().bytes)
    return base64.b64encode(h.digest() + uuid.uuid4().bytes, ['+', '-']).replace('=', '').replace('+', '')

    
def set_cookie(uid, user_info = {}):
    last_error = "ok"
    hash = generate_rnd_hash(uid)
    dt = datetime.utcnow() + timedelta(seconds = 60*60*24*7)
    exp_gmt = dt.strftime("%a, %d-%b-%Y %H:%M:%S GMT")
    user = Users.get_by_key_name(str(uid))
    if not user:
        user = Users(key_name=str(uid))
    if user_info:
        user.uid = user_info["uid"]
        user.username = user_info["username"]
        user.name = user_info["name"]
        user.image = user_info["image"]
        user.token = user_info["token"]
        user.secret = user_info["secret"]
    user.hash = hash
    user.hashex = dt
    user.put()
    try:
        response.set_cookie('sid', hash, secret = None, \
                                            **{'expires' : exp_gmt, 'path' : '/'})
    except Exception, msg:
        logging.error(msg)

def del_cookie():
    uid = get_cookie()
    user = Users.get_by_key_name(str(uid)) if uid else None
    if user:
        user.delete()
    try:
        response.set_cookie('sid', "", secret = None, \
                                            **{'path' : '/'})
    except Exception, msg:
        logging.error(msg)
        
    
def get_cookie():
    hash = request.get_cookie("sid")
    logging.debug(hash)
    key = Users.all(keys_only=True).filter("hash = ", hash).fetch(1)
    key = long(key[0].name()) if key else 0
    return key

OAuth для твиттера

Этот интерфейс авторизации придумали для того что бы свой пароль пользователь не оставлял на третьих сайтах, а авторизовался непосредственно там он создал аккаунт - у провайдера. В данном примере речь пойдёт о Twitter.
Итак мы зарегистрировали приложение в предыдущем посте. И получили два пин-кода: ключ, и секрет. С помощью их мы можем теперь получить, если пользователь разрешит, пользовательский токен, и секрет - пользовательские пин-коды. Ключей везде по двое, что бы обеспечьте защиту канала связи.
По большому счёту если нет желания со всем этим заморачиваться - то и не надо, для это есть уже готовые библиотеки, сделанные прямо для авторизации в твиттере через GAE-приложение, и даже не одна. Я взял AppEngine-OAuth-Library by Mike Knapp, которая состоит из одного файла и маленьким примерчиком.
Собственно весь процесс авторизации выглядит следующим образом:
@route('/login')
@route('/login/')
def login_view():
    callback_url = "http://%s/verify" % request.environ["HTTP_HOST"]
    client = TwitterClient(TWITTER_KEY, TWITTER_SECRET, callback_url)
    redirect(client.get_authorization_url())
    
@route('/verify')
@route('/verify/')
def verify_view():
    callback_url = "http://%s/verify" % request.environ["HTTP_HOST"]
    auth_token = request.GET.get('oauth_token', "")
    auth_verifier = request.GET.get('oauth_verifier', "")
    client = TwitterClient(TWITTER_KEY, TWITTER_SECRET, callback_url)
    try:
        user_info = client.get_user_info(auth_token, auth_verifier=auth_verifier)
    except Exception, msg:
        redirect("/")
    set_cookie(user_info["uid"], user_info)
    redirect("/")
Собственно запрос на авторизацию и её проверка. В случаее успеха имеем словарик с
service, token, secret, id, username, name, picture. Теперь в твиттер можно отправлять авторизованные запросы:
timeline_url = "http://twitter.com/statuses/user_timeline.xml"
    result = client.make_request(url=timeline_url, token=user_token, 
          secret=user_secret)

суббота, 28 мая 2011 г.

Твиттер

Как я уже сообщил что одну неделю приложение было не работоспособно из за бага. За это время пришло понимание каким наконец приложение должно быть. И будет оно таким:
  • твиттер-ориентированным, или дословно твиттер-приложением.
  • больше ориентированно на сами твиты, чем на фолловеров.
  • ну и новости, тредны тоже должны быть.
Как это удастся связать - это для меня тоже вопрос, но пока осваиваем твиттер. Причём с самого начала (*sick*). Для этого надо завести аккаунт. После подтверждения по емэйлу можно зарегистрировать свое приложение. Приблизительно форма регистрации приложения выглядит так:
  • Application Name - уникальное название приложения
  • Description - описание.
  • Application Website - домашняя страница приложения.
  • Organization - можно указать себя.
  • Application Type - либо вэб, либо десктопное.
  • Callback URL - если десктопное, то надо указать куда будет перенаправлять твиттер авторизованных, через OAuth пользователей (подробней об этом уже в следующем посте).
  • Application Icon - иконка.

После ввода капчи, приложение можно считать зарегистрированным.

Постоянные читатели

Copyright © trendec. Технологии Blogger.