Trying to use flask principal to restrict access to particular web pages - python

Hello am new at using flask and I have been trying to figure out how to restrict some web pages unless logged in. I tried flask decorators I tried flask decorators but I couldn't understand it so I tried using flask principal which am able to get it running but still cannot be able to stop the access to that webpage.
Code Description
from flask_principal import Permission, RoleNeed
# create permission with a single Need, in this case a RoleNeed
user_permission = Permission(RoleNeed('User'))
#app.route('/home')
def home_page():
return render_template('home.html')
#app.route('/user')
#user_permission.require()
def do_user_index():
return Response('Only if you are a user')
#app.route('/employee')
def employee_page():
user = User.query.all()
return render_template('employee.html', user=user)
def do_employee_page():
with user_permission.require():
return redirect(url_for('login_page'))

You can use session:
First thing we gonna do is create a session at the moment of login:
#app.route(#route that you gonna use to login data verify)
def login():
#login data verification
flask.session["user data"] = #Data you want to use to identify the user
#the next step that you wanna do
Now we gonna verify the session data in the pages, if the user are log in they gonna have their data in flask.session and if not, they not going to have the data in session.
#app.route('/user')
def do_user_index():
if "user data" not in flask.session:
#Redirect to the login page
return Response('Only if you are a user')
You can consult the documentation to learn more about the how to use session.
https://flask.palletsprojects.com/en/2.0.x/quickstart/#sessions

Related

django and instapy integration

I want to build a tool like hootsuide for my own stuff. As you know, Instagram only allows instagram partners to publish a content via api.
I use instapy as a single python file but I've never used with django before. I'm having some troubles with integration.
views.py :
from django.shortcuts import render, redirect
from instapy import InstaPy
# Create your views here.
def instapy_login(request):
session = InstaPy(username='test', password='test')
session.login()
return redirect("/")
However, I want to use this login credentials for next requests.
For example :
def fetch_followers(request):
session = InstaPy(username='test', password='test') # I don't want to login again.
session.login() # I don't want to login again.
followers = session.grab_followers(username="test", amount="full")
print(followers)
return redirect("/")
I don't want to login in every request. Any idea about fixing it? Thanks alot!
I am also new to django but i think pass instapy_login to your function in which you want to use

In flask-stormpath, how do I route a user to a specific page after loging in based on the user's Stormpath group

PROBLEM STATEMENT
I'm working on a flask app that uses Stormpath for authentication. In my app I have two user groups: normal users and admins. After a user logs in, I'd like to redirect them to a specific page based on the group they belong to. So if a user is a normal user they'd be redirected to /dashboard and if they are an admin, they'd be redirected to /admin_dashboard. As of right now, I have STORMPATH_REDIRECT_URL = '/dashboard' so every time they log in they get redirected to /dashboard regardless of the group they belong to. How can I redirect them to a specific page based on their Stormpath group?
CURRENT CODE SNIPPETS:
Note: I am using the default Flask-Stormpath login views and the app allows social login through Google.
/app/__init__.py:
def create_app(config_name):
...
# App config here
...
stormpath_manager = StormpathManager()
stormpath_manager.init_app(app)
...
return app
/config.py:
class Config(Object):
...
STORMPATH_REDIRECT_URL = '/dashboard'
...
/app/dashboard/views.py:
#dashboard_blueprint.route('/dashboard')
#login_required
#groups_required(['normal-users'])
def dashboard():
return render_template('dashboard/index.html', title="Dashboard")
#dashboard_blueprint.route('/admin_dashboard')
#login_required
#groups_required(['admins'])
def admin_dashboard():
return render_template('dashboard/admin_index.html', title="Admin Dashboard")
SOLUTION
flask_stormpath has a User class as seen here, which takes in an Account as an argument. From the stormpath-sdk-python, we can see that an Account has a has_group(self, resolvable) function as seen here.
So to display a specific page after a user logs in, based on the group the user belongs to, I made the following changes to /app/dashboard/views.py while keeping the others unchanged:
from flask_stormpath import User
from flask_stormpath import current_user
#dashboard_blueprint.route('/dashboard')
#login_required
def dashboard():
if User.has_group(current_user, 'normal-users'):
return render_template('dashboard/index.html', title="Dashboard")
elif User.has_group(current_user, 'admins'):
return render_template('dashboard/admin_index.html', title="Admin Dashboard")
else:
return render_template('dashboard/error.html', title="Error Page")

Python Flask - How to pass values from one route to another?

Hi I am new to flask and I am trying to create a simple login functionality. Users fill out their username and password (which at this point needs to match the username and password I hardcoded) and if their credentials are approved they are taken to their profile page. The profile page should show the message Hello followed by the username.
The validation is working just fine and the user is taken to the profile page but I can't pass the username from the form (login.html) to the template "profile.html".
Below follows the code. I am sending the code that works but there is no tentative to pass the username.
Thank you!
from flask import *
SECRET_KEY = "super secret"
app = Flask(__name__)
app.config.from_object(__name__)
#app.route('/')
def index():
return render_template('login.html')
#app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] == 'user' and request.form['password'] == 'pass':
session['loggedin'] = True
return redirect(url_for('profile'))
else:
error="Invalid credentials. Please try again."
return render_template('login.html', error=error)
#app.route('/profile')
def profile():
return render_template('profile.html')
#app.route('/logout')
def logout():
session.pop('loggedin', None)
return redirect(url_for('login'))
if __name__ == '__main__':
app.run(debug=True)
I think you miss the point of your hard work login page.
What about the next page the user will choose to visit? Will you send the username value again? of course not..
I suggest you to define a global var(session? DB data?) that contain the current-logged-in-user-data, so you can use all user's data, not only his username(age?posts? etc..)
One last thing, i use flask-login, i really like it, it simple mange my login session/views and guess what? there is current_user with the current-logged-in-user-data :)
Flask-login summery:
Flask-Login provides user session management for Flask.
It handles the common tasks of logging in, logging out, and remembering your users’ sessions over extended periods of time.
Why not make use of flask's many useful modules? They make flask an attractive microframework for speedy web development.
Flask-login, as stated above, streamlines authentication processes and manages sessions. Flask sessions also automatically stores session data for logged-in users. This allows you to implement a "Remember Me" feature in your login form.
Also, for security purposes, you would want to decorate some of your functions with #login_required, which is part of the flask-login module. This makes sure that the user is automatically redirected to the login page if he or she is not logged in already.
Here is an example of an index function that implements this:
from flask import render_template, session
from flask.ext.login import login_required
#app.route('/')
#login_required
def index():
return render_template("index.html")
You could also use flask.ext.openidto make authentication even more convenient.

Testing Flask login and authentication?

I'm developing a Flask application and using Flask-security for user authentication (which in turn uses Flask-login underneath).
I have a route which requires authentication, /user. I'm trying to write a unit test which tests that, for an authenticated user, this returns the appropriate response.
In my unittest I'm creating a user and logging as that user like so:
from unittest import TestCase
from app import app, db
from models import User
from flask_security.utils import login_user
class UserTest(TestCase):
def setUp(self):
self.app = app
self.client = self.app.test_client()
self._ctx = self.app.test_request_context()
self._ctx.push()
db.create_all()
def tearDown(self):
if self._ctx is not None:
self._ctx.pop()
db.session.remove()
db.drop_all()
def test_user_authentication():
# (the test case is within a test request context)
user = User(active=True)
db.session.add(user)
db.session.commit()
login_user(user)
# current_user here is the user
print(current_user)
# current_user within this request is an anonymous user
r = test_client.get('/user')
Within the test current_user returns the correct user. However, the requested view always returns an AnonymousUser as the current_user.
The /user route is defined as:
class CurrentUser(Resource):
def get(self):
return current_user # returns an AnonymousUser
I'm fairly certain I'm just not fully understanding how testing Flask request contexts work. I've read this Flask Request Context documentation a bunch but am still not understanding how to approach this particular unit test.
The problem is different request contexts.
In your normal Flask application, each request creates a new context which will be reused through the whole chain until creating the final response and sending it back to the browser.
When you create and run Flask tests and execute a request (e.g. self.client.post(...)) the context is discarded after receiving the response. Therefore, the current_user is always an AnonymousUser.
To fix this, we have to tell Flask to reuse the same context for the whole test. You can do that by simply wrapping your code with:
with self.client:
You can read more about this topic in the following wonderful article:
https://realpython.com/blog/python/python-web-applications-with-flask-part-iii/
Example
Before:
def test_that_something_works():
response = self.client.post('login', { username: 'James', password: '007' })
# this will fail, because current_user is an AnonymousUser
assertEquals(current_user.username, 'James')
After:
def test_that_something_works():
with self.client:
response = self.client.post('login', { username: 'James', password: '007' })
# success
assertEquals(current_user.username, 'James')
The problem is that the test_client.get() call causes a new request context to be pushed, so the one you pushed in your the setUp() method of your test case is not the one that the /user handler sees.
I think the approach shown in the Logging In and Out and Test Adding Messages sections of the documentation is the best approach for testing logins. The idea is to send the login request through the application, like a regular client would. This will take care of registering the logged in user in the user session of the test client.
I didn't much like the other solution shown, mainly because you have to keep your password in a unit test file (and I'm using Flask-LDAP-Login, so it's nonobvious to add a dummy user, etc.), so I hacked around it:
In the place where I set up my test app, I added:
#app.route('/auto_login')
def auto_login():
user = ( models.User
.query
.filter_by(username="Test User")
.first() )
login_user(user, remember=True)
return "ok"
However, I am making quite a lot of changes to the test instance of the flask app, like using a different DB, where I construct it, so adding a route doesn't make the code noticeably messier. Obv this route doesn't exist in the real app.
Then I do:
def login(self):
response = self.app.test_client.get("/auto_login")
Anything done after that with test_client should be logged in.
From the docs: https://flask-login.readthedocs.io/en/latest/
It can be convenient to globally turn off authentication when unit testing. To enable this, if the application configuration variable LOGIN_DISABLED is set to True, this decorator will be ignored.

Show That User Is Logged Into iOS app

The login works from the backend and it goes to the home screen after login on iOS. But how do I do guarantee that the user is actually being logged in?
For example, I have a Label that I would like the user's username to be displayed in, but I don't know how to get the user's username .
I have an idea where I can call the server and it will return the username in JSON format, but isn't this kind of inefficient? What is a better way to do this?
PS. I am a first time iOS programmer
Additional info:
I am also currently using Flask and the Flask-Login extension for the backend. Using the login_user(user) method. This has worked in the past for web dev, but how do I get it to work for iOS dev.
#app.route('/login/', methods=['POST'])
def login():
params = json.loads(request.data)
username = params['username']
password = params['password']
u = User.query.filter_by(username=username).first()
if u:
if utils.check_password_hash(password, u.pw_hash):
login_user(u)
return ('', 200)
else:
return ('', 400)
else:
return ('', 400)
Take a look at Parse.com's iOS SDK (https://www.parse.com/docs/ios_guide#top/iOS). It provides a login form as well as the ability to use a PFUser object to determine if the user is logged in or not. The best thing about Parse is it's free. :)
Calling [PFUser currentUser] will return the user that's logged in or nil if there is no user.

Categories

Resources