async def add_session_to_request(request): #setup session auth = Auth(app) @app.route('/login', methods=['GET', 'POST']) async def login(request): message = '' if request.method == 'POST': username = request.form.get('username') password = request.form.get('password') # fetch user from database user = some_datastore.get(name=username) if user and user.check_password(password): auth.login_user(request, user) return response.redirect('/profile') return response.html(HTML_LOGIN_FORM) @app.route('/logout') @auth.login_required async def logout(request): auth.logout_user(request) return response.redirect('/login') @app.route('/profile') @auth.login_required(user_keyword='user') async def profile(request, user): return response.json({'user': user})
def test_login_required(app): # the default is 'auth.login', change to 'login' to avoid using blueprint app.config.AUTH_LOGIN_ENDPOINT = 'login' auth = Auth(app) @app.post('/login') async def login(request): name = request.form.get('name') password = request.form.get('password') if name == 'demo' and password == '1234': auth.login_user(request, User(id=1, name=name)) return response.text('okay') return response.text('failed') @app.route('/logout') @auth.login_required async def logout(request): auth.logout_user(request) return response.redirect('/user') @app.route('/user') @auth.login_required(user_keyword='user') async def user(request, user): return response.text(user.name) payload = {'name': 'demo', 'password': '******'} req, resp = app.test_client.get('/user', allow_redirects=False) assert resp.status == 302 assert resp.headers['Location'] == app.url_for('login') payload = {'name': 'demo', 'password': '******'} req, resp = app.test_client.post('/login', data=payload) assert resp.status == 200 and resp.text == 'okay' req, resp = app.test_client.get('/user') assert resp.status == 200 and resp.text == 'demo'
def test_user_keyword(app): auth = Auth(app) @app.post('/login') async def login(request): name = request.form.get('name') password = request.form.get('password') if name == 'demo' and password == '1234': auth.login_user(request, User(id=1, name=name)) return response.text('okay') return response.text('failed') @app.route('/user') @auth.login_required(user_keyword='user') async def user(request, user): return response.text(user.name) @app.route('/<user>') @auth.login_required(user_keyword='user') async def user_id(request, user): return response.text(user.id) payload = {'name': 'demo', 'password': '******'} req, resp = app.test_client.post('/login', data=payload) assert resp.status == 200 and resp.text == 'okay' req, resp = app.test_client.get('/user') assert resp.status == 200 and resp.text == 'demo' req, resp = app.test_client.get(app.url_for('user_id', user=1)) # RuntimeError being raised because we try to overwrite user parameter assert resp.status == 500
def test_async_user_loader(app): auth = Auth(app) @auth.user_loader async def load_user(token): if token is 'root': return 'pwned' return None @auth.serializer def serialize(user): return 'root' @app.post('/login') async def login(request): auth.login_user(request, user) return response.text('All your base are belong to us') @app.route('/user') @auth.login_required(user_keyword='user') async def user(request, user): return response.text(user) req, resp = app.test_client.post('/login') assert resp.status == 200 and resp.text == 'All your base are belong to us' req, resp = app.test_client.get('/user') assert resp.status == 200 and resp.text == 'pwned'
def test_login(app): auth = Auth(app) @app.post('/login') async def login(request): name = request.form.get('name') password = request.form.get('password') if name == 'demo' and password == '1234': auth.login_user(request, User(id=1, name=name)) return response.text('okay') return response.text('failed') @app.route('/user') async def user(request): user = auth.current_user(request) if user is not None: return response.text(user.name) return response.text('') payload = {} req, resp = app.test_client.post('/login', data=payload) assert resp.status == 200 and resp.text == 'failed' req, resp = app.test_client.get('/user') assert resp.status == 200 and resp.text == '' payload = {'user': '******'} req, resp = app.test_client.post('/login', data=payload) assert resp.status == 200 and resp.text == 'failed' req, resp = app.test_client.get('/user') assert resp.status == 200 and resp.text == '' payload = {'name': 'demo', 'password': '******'} req, resp = app.test_client.post('/login', data=payload) assert resp.status == 200 and resp.text == 'failed' req, resp = app.test_client.get('/user') assert resp.status == 200 and resp.text == '' payload = {'name': 'demo', 'password': '******'} req, resp = app.test_client.post('/login', data=payload) assert resp.status == 200 and resp.text == 'okay' req, resp = app.test_client.get('/user') assert resp.status == 200 and resp.text == 'demo'
def app_creator(config: dict, manager=None): app = Sanic(__name__) app.manager = manager app.config.update(config) app.static('/static', '/root/golden/jspider/jspider/web/dist') app.blueprint(bp) app.node_state = {} cors = CORS(app, supports_credentials=True) auth = Auth(app) auth.login_endpoint = 'login' @app.listener('before_server_start') async def setup_db(app, loop): app.spider_state = app.manager.projects() @app.middleware('request') async def add_session_to_request(request): request['session'] = {} # app.config.from_pyfile() @app.route("/") async def index(request): htm = os.path.join(app.config['HOME_PATH'], 'jspider', 'web', 'dist', 'index.html') with open(htm, 'r+') as f: return html(f.read()) @app.route('/heart_beat/', methods=['GET']) async def heart_beat(req): name = req.args.get('name') sys_type = req.args.get('sys_type') sys_version = req.args.get('sys_version') if name not in app.node_state: app.node_state[name] = { "sys_type": sys_type, 'sys_version': sys_version, 'spider_state': app.manager.projects() } app.node_state[name].update(status=1) return json({ 'name': name, 'spider_state': app.node_state[name]['spider_state'] }) # 1需要更新 @app.route('/login', methods=['POST']) async def login(request): message = '' username = request.form.get('username') password = request.form.get('password') # fetch user from database user = User(id=1, name=username) if user: auth.login_user(request, user) return json({"status": 0, "msg": "%s login success" % username}) @app.route('/menus/', methods=['GET']) @auth.login_required async def menus(req): return json([ { 'header': 'Apps' }, { 'title': '首页', 'group': 'apps', 'icon': 'dashboard', 'name': 'Dashboard', }, { 'title': '项目', 'group': 'apps', 'icon': 'folder', 'name': 'Project', }, { 'title': '日志', 'group': 'apps', 'icon': 'folder', 'name': 'log', }, ]) @app.route('/logout/', methods=['GET']) @auth.login_required async def logout(req): auth.logout_user(req) return json(json({"status": 0, "msg": "logout success"})) return app
from sanic import Sanic from sanic_auth import Auth from sanic import Blueprint, response # --------------------------Auth Configurations------------------------------- orm_main = Sanic(__name__) ormAuth = Auth(orm_main) ormBlr = Blueprint ClxRsp = response ormBluePrint = orm_main.blueprint ormConfig = orm_main.config
from tortoise import Tortoise from sanic_mako import SanicMako from sanic_auth import Auth from config import DB_URL import aiotask_context as context mako = SanicMako() auth = Auth() async def init_db(create_db=False): await Tortoise.init(db_url=DB_URL, modules={'models': ['models']}, _create_db=create_db)
from sanic import Sanic, response from sanic.websocket import WebSocketProtocol from sanic_auth import Auth, User from sanic_jinja2 import SanicJinja2 import asyncio_redis from channel import Channel, response_message from redis_handle import redis_pub_sub from db_driver import redis_set_get, pg_set_get from ws_handle import receive_ws_channel, ws_room_send_chat session = {} app = Sanic(__name__) app: asyncio_redis.Pool app.config.AUTH_LOGIN_ENDPOINT = 'login' auth = Auth(app) jinja = SanicJinja2(app, pkg_path='template') @app.listener('before_server_start') async def setup(app, loop): app.conn = await redis_pub_sub.create_connection_pool() @app.listener('after_server_stop') async def close_db(app, loop): await app.close() @app.middleware('request') async def add_session(request):
def init_app(): global app app = Sanic(__name__, log_config=None) app.config.log_config = None app.config.AUTH_LOGIN_ENDPOINT = "login" BASE_DIR = os.path.dirname(__file__) # Static routes app.static("/index.html", os.path.join(BASE_DIR, "client/dist/index.html")) app.static("/favicon.ico", os.path.join(BASE_DIR, "client/dist/favicon.ico")) app.static( "/manifest.json", os.path.join(BASE_DIR, "../client/dist/manifest.json"), content_type="application/manifest+json", ) app.static("/robots.txt", os.path.join(BASE_DIR, "client/dist/robots.txt")) app.static("/service-worker.js", os.path.join(BASE_DIR, "client/dist/service-worker.js")) app.static("/img", os.path.join(BASE_DIR, "client/dist/img")) app.static("/js", os.path.join(BASE_DIR, "client/dist/js")) app.static("/css", os.path.join(BASE_DIR, "client/dist/css")) app.static("/.well-known", os.path.join("./", ".well-known")) # TODO find a way to do better auth = Auth(app) auth.user_loader(account_manager.get) # Dynamic manifest route @app.route("/precache-manifest.<manifest_id>.js", stream=True) async def precache_manifest(request, manifest_id): path = os.path.join( BASE_DIR, f"../client/dist/precache-manifest.{manifest_id}.js") if os.path.exists(path): return await file_stream(path) else: raise NotFound(f"{path} not found") @app.middleware("request") async def add_session_to_request(request): # setup session session_key = request.cookies.get("session_key") if session_key: request["session"] = await storage.get_user_session(session_key) else: request["session"] = {} @app.middleware("response") async def add_session_key_to_response(request, response): # add default session key if not existing auth_key = request.cookies.get("session_key") if auth_key is None and response.cookies.get("session_key") is None: session_key = gen_session_key() response.cookies["session_key"] = session_key @app.route("/login", methods=["POST"]) async def login(request): credentials = request.json # get user account from credentials account = account_manager.authenticate(credentials) if account: session_key = gen_session_key() session = await storage.get_user_session(session_key) session[auth.auth_session_key] = account.name await storage.save_user_session(session_key, session) response = json(account.to_json()) # Add session key to response response.cookies["session_key"] = session_key return response raise Forbidden("Authentication failed. Check your credentials.") @app.route("/check") async def check(request): return json("Ok") @app.route("/logout") @auth.login_required(handle_no_auth=handle_no_auth) async def logout(request): auth.logout_user(request) request["session"] = {} response = json("Ok") response.cookies["session_key"] = gen_session_key() return response @app.route("/api/users/<user_id>/account") @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def account(request, user_id, account): if account.name != user_id: raise Forbidden("You can't consult another person account.") response = account.to_json() return json(response) @app.route("/") async def index(request): return redirect("/index.html") @app.route("/api/users/<user_id>/mailboxes") @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def mailboxes(request, user_id, account): if account.name != user_id: raise Forbidden("You can't consult another person account.") mbxs = await storage.get_mailboxes(account) for mb in mbxs: if mb["last_message"]: mb["last_message"] = mb["last_message"].isoformat() return json(mbxs) @app.route("/api/users/<user_id>/unreads") @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def unreads(request, user_id, account): if account.name != user_id: raise Forbidden("You can't consult another person account.") mbxs = await storage.get_unreads(account) return json(mbxs) @app.route("/api/users/<user_id>/mailbox/<mailbox_id>") @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def mailbox(request, user_id, mailbox_id, account): if account.name != user_id: raise Forbidden("You can't consult another person account.") mailbox_to_return = await storage.get_mailbox(account, mailbox_id) for msg in mailbox_to_return["messages"]: msg["date"] = msg["date"].isoformat() return json(mailbox_to_return) @app.route("/api/users/<user_id>/mail/<mail_id>") @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def mail(request, user_id, mail_id, account): if account.name != user_id: raise Forbidden("You can't consult another person account.") mail_to_return = await storage.get_mail(account, mail_id) for att in mail_to_return["attachments"]: if not att.get("filename"): guessed_ext = mimetypes.guess_extension(att["type"]) if not guessed_ext: guessed_ext = ".bin" att["filename"] = "file_{}{}".format(att["index"], guessed_ext) att["url"] = f"/api/users/{user_id}/mail/{mail_id}/attachment/{att['index']}/{att['filename']}" mail_to_return["date"] = mail_to_return["date"].isoformat() # Change link to attached file await mailutils.convert_cid_link(mail_to_return) return json(mail_to_return) @app.route("/api/users/<user_id>/mail/<mail_id>/mark_read", methods=["POST"]) @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def mail_mark_read(request, user_id, mail_id, account): if account.name != user_id: raise Forbidden("You can't consult another person account.") """mail_to_mark = await storage.get_mail(account, mail_id) mail_to_mark["unread"] = False await storage.update_mail(account, mail_to_mark)""" await storage.mark_mail_read(account, mail_id) return json("Ok") @app.route( "/api/users/<user_id>/mail/<mail_id>/attachment/<att_index>/<filename>", methods=["GET"], ) @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def mail_download_attachment(request, user_id, mail_id, att_index, filename, account): if account.name != user_id: raise Forbidden("You can't consult another person account.") attachment, att_content = await storage.get_mail_attachment( account, mail_id, int(att_index)) async def streaming_att(response): await response.write(att_content) return stream(streaming_att, content_type=attachment["type"]) @app.route("/api/users/<user_id>/sendmail/", methods=["POST"]) @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def sendmail(request, user_id, account): """ Send an email """ if account.name != user_id: raise Forbidden("You can't consult another person account.") data = request.json from_addr = mailutils.parse_email(account.address) all_addrs = [ mailutils.parse_email(a["address"]) for a in data["recipients"] ] tos = [ mailutils.parse_email(a["address"]) for a in data["recipients"] if a["type"] == "to" ] ccs = [ mailutils.parse_email(a["address"]) for a in data["recipients"] if a["type"] == "cc" ] attachments = data.get("attachments", []) msg = mailutils.make_msg(data["subject"], data["content"], from_addr, tos, ccs, attachments) result = await send_mail(account, msg, from_addr, all_addrs) return json(result) @app.route("/api/users/<user_id>/mail/<mail_id>/resend", methods=["POST"]) @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def mail_resend(request, user_id, mail_id, account): """ Resend an email by uid for selected recipient""" if account.name != user_id: raise Forbidden("You can't consult another person account.") mail_to_resend = await storage.get_mail(mail_id) # Check permissions if mail_to_resend["account"] != account.name: raise Forbidden("You don't have permission to resend this mail.") data = request.json tos = [mailutils.parse_email(data["to"])] result = await resend_mail(account, mail_to_resend, tos) return json(result) @app.route("/api/users/<user_id>/contacts/search", methods=["GET"]) @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def contacts_search(request, user_id, account): if account.name != user_id: raise Forbidden("You can't consult another person account.") text = request.args.get("text", "") if not text: return json([]) results = await storage.contacts_search(account, text) return json(results) @app.get("/api/publickey") async def subscription_get(request, user_id): """ GET returns vapid public key which clients uses to send around push notification """ pub = await push.get_application_server_key() return text(pub, headers={"Access-Control-Allow-Origin": "*"}) @app.post("/api/subscription/") @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def subscription_post(request, user_id, account): """ POST creates a subscription """ if account.name != user_id: raise Forbidden("You can't consult another person account.") subscription = request.json["subscription"] await storage.add_subscription(account, subscription) await push.send_web_push(subscription, "You have subscribed to notification") return json({}, status=201) @app.post("/api/unsubscription/") @auth.login_required(user_keyword="account", handle_no_auth=handle_no_auth) async def unsubscription_post(request, user_id, account): """ POST creates a subscription """ if account.name != user_id: raise Forbidden("You can't consult another person account.") subscription = request.json["subscription"] # Remove subscription for this account await storage.remove_subscription(account, subscription) return json({}, status=201)
apfell_db.connect_async(loop=dbloop) db_objects = Manager(apfell_db, loop=dbloop) apfell = Sanic(__name__) apfell.config.AUTH_LOGIN_ENDPOINT = 'login' apfell.config[ 'WTF_CSRF_SECRET_KEY'] = 'really secure super secret key here, and change me!' apfell.config['SERVER_IP_ADDRESS'] = server_ip apfell.config['SERVER_PORT'] = listen_port apfell.config['DB_USER'] = db_user apfell.config['DB_PASS'] = db_pass apfell.config['DB_NAME'] = db_name apfell.config['DB_POOL_CONNECT_STRING'] = 'dbname=' + apfell.config[ 'DB_NAME'] + ' user='******'DB_USER'] + ' password='******'DB_PASS'] auth = Auth(apfell) session = {} links = { 'server_ip': apfell.config['SERVER_IP_ADDRESS'], 'server_port': apfell.config['SERVER_PORT'] } @apfell.middleware('request') async def add_session(request): request['session'] = session import app.routes import app.api
def init_app(): global app app = Sanic(__name__, log_config=None) app.config.log_config = None app.config.AUTH_LOGIN_ENDPOINT = 'login' BASE_DIR = os.path.dirname(__file__) app.static('/static', os.path.join(BASE_DIR, '../client/dist/static')) app.static('/index.html', os.path.join(BASE_DIR, '../client/dist/index.html')) auth = Auth(app) auth.user_loader(account_manager.get) @app.middleware('request') async def add_session_to_request(request): # setup session session_key = request.cookies.get('session_key') if session_key: request['session'] = sessions[session_key] else: request['session'] = {} @app.middleware('response') async def add_session_key_to_response(request, response): # add default session key if not existing auth_key = request.cookies.get('session_key') if auth_key is None: session_key = gen_session_key() response.cookies['session_key'] = session_key @app.route('/login', methods=['POST']) async def login(request): credentials = request.json # get user account account = account_manager.authenticate(credentials) if account: session_key = gen_session_key() session = sessions[session_key] session[auth.auth_session_key] = account.name response = json(account.to_json()) # Add session key to response response.cookies['session_key'] = session_key return response raise Forbidden("Authentification failed. Check your credentials.") @app.route('/logout') @auth.login_required(handle_no_auth=handle_no_auth) async def logout(request): auth.logout_user(request) request['session'] = {} response = json('Ok') response.cookies['session_key'] = gen_session_key() return response @app.route('/api/account') @auth.login_required(user_keyword='account', handle_no_auth=handle_no_auth) async def account(request, account): return json(account.to_json()) @app.route('/') async def index(request): return redirect('/index.html') @app.route("/api/mailboxes") @auth.login_required(user_keyword='account', handle_no_auth=handle_no_auth) async def mailboxes(request, account): mbxs = await storage.get_mailboxes(account) for m in mbxs: if isinstance(m['last_message'], datetime.datetime): # Also strange hack m['last_message'] = m['last_message'].isoformat() return json(mbxs) @app.route("/api/mailbox/<mailbox_id>") @auth.login_required(user_keyword='account', handle_no_auth=handle_no_auth) async def mailbox(request, mailbox_id, account): mailbox_to_return = await storage.get_mailbox(mailbox_id) if mailbox_to_return['account'] != account.name: raise Forbidden("You don't have permission to see this mailbox.") for m in mailbox_to_return['messages']: if isinstance(m['date'], datetime.datetime): # Also strange hack m['date'] = m['date'].isoformat() return json(mailbox_to_return) @app.route("/api/mail/<mail_id>") @auth.login_required(user_keyword='account', handle_no_auth=handle_no_auth) async def mail(request, mail_id, account): mail_to_return = await storage.get_mail(mail_id) if mail_to_return['account'] != account.name: raise Forbidden("You don't have permission to see this mail.") if isinstance(mail_to_return['date'], datetime.datetime): # Also strange hack mail_to_return['date'] = mail_to_return['date'].isoformat() for att in mail_to_return['attachments']: if not att.get('filename'): guessed_ext = mimetypes.guess_extension(att['type']) if not guessed_ext: guessed_ext = ".bin" att['filename'] = 'file_{}{}'.format( att['index'], guessed_ext ) att['url'] = "/api/mail/{}/attachment/{}/{}".format(mail_id, att['index'], att['filename']) return json(mail_to_return) @app.route("/api/mail/<mail_id>/mark_read", methods=['POST']) @auth.login_required(user_keyword='account', handle_no_auth=handle_no_auth) async def mail_mark_read(request, mail_id, account): mail_to_mark = await storage.get_mail(mail_id) if mail_to_mark['account'] != account.name: raise Forbidden("You don't have permission to see this mail.") mail_to_mark['unread'] = False await storage.update_mail(mail_to_mark) return json(mail_to_mark) @app.route("/api/mail/<mail_id>/attachment/<att_index>/<filename>", methods=['GET']) @auth.login_required(user_keyword='account', handle_no_auth=handle_no_auth) async def mail_download_attachment(request, mail_id, att_index, filename, account): attachment, att_content = await storage.get_mail_attachment(mail_id, int(att_index)) async def streaming_att(response): response.write(att_content) return stream(streaming_att, content_type=attachment['type']) @app.route("/api/sendmail/", methods=['POST']) @auth.login_required(user_keyword='account', handle_no_auth=handle_no_auth) async def sendmail(request, account): data = request.json mail_sender = MailSender() from_addr = mailutils.parse_email(account.address) all_addrs = [mailutils.parse_email(a['address']) for a in data['recipients']] tos = [mailutils.parse_email(a['address']) for a in data['recipients'] if a['type'] == 'to'] ccs = [mailutils.parse_email(a['address']) for a in data['recipients'] if a['type'] == 'cc'] attachments = data.get('attachments', []) msg = mailutils.make_msg(data['subject'], data['content'], from_addr, tos, ccs, attachments) # First we store it saved_msg = await storage.store_msg( msg, account=account, from_addr=from_addr, to_addrs=all_addrs, incoming=False ) # Then we send it delivery_status = await mail_sender.send( msg, from_addr=from_addr.addr_spec, to_addrs=[a.addr_spec for a in all_addrs] ) # TODO update delivery status in store # Finally we return it return json(saved_msg)
def test_setup_once(app): auth = Auth(app) with pytest.raises(RuntimeError): auth.setup(app)
def test_decorators(app): auth = Auth(app) USER_DB = [ { 'id': '1', 'name': 'demo', 'password': '******' }, { 'id': '2', 'name': 'admin', 'password': '******' }, ] def find_user(name, password): for user in USER_DB: if user['name'] == name and user['password'] == password: return user @auth.serializer def serialize(user): return user['id'] @auth.user_loader def load_user(token): for user in USER_DB: if user['id'] == token: return user @auth.no_auth_handler def handle_unauthorized(request): return response.text('unauthorized', status=401) def handle_no_auth(request): return response.text('no_auth', status=403) @app.post('/login') async def login(request): name = request.form.get('name') password = request.form.get('password') user = find_user(name, password) if user is not None: auth.login_user(request, user) return response.text('okay') return response.text('failed') @app.route('/user') @auth.login_required(user_keyword='user') async def user(request, user): return response.text(user['name']) @app.route('/user/data') @auth.login_required(handle_no_auth=handle_no_auth) async def user_data(request, user): return response.text(user['name']) req, resp = app.test_client.get('/user') assert resp.status == 401 and resp.text == 'unauthorized' req, resp = app.test_client.get('/user/data') assert resp.status == 403 and resp.text == 'no_auth' payload = {'name': 'noone', 'password': '******'} req, resp = app.test_client.post('/login', data=payload) assert resp.status == 200 and resp.text == 'failed' payload = {'name': 'demo', 'password': '******'} req, resp = app.test_client.post('/login', data=payload) assert resp.status == 200 and resp.text == 'okay' req, resp = app.test_client.get('/user') assert resp.status == 200 and resp.text == 'demo'