Currently, my index.html
file contains
<a href="static/file.ext">Download</a>
I want to change this so that the download url is only valid for a certain time. For example, how would I change it to
<a href="get_file?file=file.ext&token=TEMPORARYTOKEN">Download</a>
In my Flask file, I could then have
@app.route('/get_file')
def get_file():
filename = request.args.get('file')
token = request.args.get('token')
if token is valid: # what can be done here
return send_from_directory('static', filename)
How can I generate and handle the token? Or am I approaching this completely wrong?
The url_for() function is used to build a URL to the specific function dynamically. The first argument is the name of the specified function, and then we can pass any number of keyword argument corresponding to the variable part of the URL.
The best way to do that is to use itsdangerous
package. You can generate a URL that last whatever time you want. Furthermore you could encode secretly any information within the URL. The good thing about that is that NO need to deal or store timestamps into the database
To generate a URL that last for 30 mins and encode user id within the token
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
s = Serializer('WEBSITE_SECRET_KEY', 60*30) # 60 secs by 30 mins
token = s.dumps({'user_id': currentuser.id}).decode('utf-8') # encode user id
Use the following to generate the URL you want
url_for('get_file', token=token)
To validate a URL
@app.route('/get_file/<token>')
def get_file(token):
s = Serializer('WEBSITE_SECRET_KEY')
try:
user_id = s.loads(token)['user_id']
except:
return None
user = User.query.get(user_id)
if not user:
flash('This is an invalid or expired URL, please generate a new one!', 'warning')
return redirect(url_for('another_route'))
return send_from_directory('static', filename, as_attachment=True)
There are a couple ways you can do this.
Generate a UUID for your token and store it in a db table along with the desired expiration datetime. Then when someone calls the URL with the token, you can just check it against the db for validity and expiration.
If you don't want to use a db to store the tokens, you can use GPG to encrypt a string that contains the expiration datetime and use the resulting encrypted string as your token. This means your token will be a lot longer than a UUID, but you'd avoid having to use a db.
I recommend using UUID and a db table.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With