This article was published as a part of the Data Science Blogathon.
As y’all might have come across authentication in Dash that is implemented using the dash-auth library, and are aware that this method is a popup login method. But what if I want a login page as we have in HTML, JavaScript, PHP, etc? Here’s the answer to your question.
So, I created a dash app and added the user authentication using dash-auth. I wanted to perform testing operations for the same. But as it was a popup I wasn’t able to get the id, class names or any related information that could be used for testing the login module.
Also, I tried applying some methods that were given in an article, but still nothing. Even after searching over the internet for hours, there was no significant answer to my question. That’s when I knew I had to find a way around to circumvent this problem. I knew about dcc.Link() and thought of using it for making the login page.
This blog contains the solution on how to create an actual login page that is just like HTML page and where you can jump from one page to another using links.
First things first, importing necessary libraries. You all must be familiar with these.
import dash import dash_core_components as dcc import dash_html_components as html from dash.dependencies import Output,Input,State
Next step is initializing the app. dash.Dash() invokes the app instance.
app = dash.Dash(__name__, external_stylesheets=external_stylesheets,suppress_callback_exceptions=True)
You need to make sure that suppress_callback_exceptions is set to true so you can navigate within different pages. If you don’t set it as true, errors related to calls will surely arise.
Let’s start with the layout.
app.layout = html.Div([ dcc.Location(id='url', refresh=False), html.Div(id='page-content') ])
The dcc.Location decides the current page that is displayed. It represents the address bar in the browser. The div below displays the specified URL content. The selected pathname will be passed as a parameter to this location component and accordingly, the page contents will be displayed. You will see this in further explanation. The refresh constraint is just for, whether to refresh the page when the location is updated, or not.
Let us now create the index page that will contain the input boxes for Username and Password and the verify button to authenticate the user. This will be the very first page that will appear.
index_page = html.Div([ html.Div( dcc.Input(id="user", type="text", placeholder="Enter Username",className="inputbox1", style={'margin-left':'35%','width':'450px','height':'45px','padding':'10px','margin-top':'60px', 'font-size':'16px','border-width':'3px','border-color':'#a0a3a2' }), ), html.Div( dcc.Input(id="passw", type="text", placeholder="Enter Password",className="inputbox2", style={'margin-left':'35%','width':'450px','height':'45px','padding':'10px','margin-top':'10px', 'font-size':'16px','border-width':'3px','border-color':'#a0a3a2', }), ), html.Div( html.Button('Verify', id='verify', n_clicks=0, style={'border-width':'3px','font-size':'14px'}), style={'margin-left':'45%','padding-top':'30px'}), html.Div(id='output1') ]) @app.callback( dash.dependencies.Output('output1', 'children'), [dash.dependencies.Input('verify', 'n_clicks')], state=[State('user', 'value'), State('passw', 'value')]) def update_output(n_clicks, uname, passw): li={'shraddha':'admin123'} if uname =='' or uname == None or passw =='' or passw == None: return html.Div(children='',style={'padding-left':'550px','padding-top':'10px'}) if uname not in li: return html.Div(children='Incorrect Username',style={'padding-left':'550px','padding-top':'40px','font-size':'16px'}) if li[uname]==passw: return html.Div(dcc.Link('Access Granted!', href='/next_page',style={'color':'#183d22','font-family': 'serif', 'font-weight': 'bold', "text-decoration": "none",'font-size':'20px'}),style={'padding-left':'605px','padding-top':'40px'}) else: return html.Div(children='Incorrect Password',style={'padding-left':'550px','padding-top':'40px','font-size':'16px'})
The above code creates 2 input boxes, the first one is for the Username and the 2nd is for the password. Unlike a normal button that allows a single input box, you need to define the ‘State’ inside a list as written above so as to take the input from multiple input boxes and then updating the output on clicking the button (verify in this case).
In the update_output we first define a dictionary ‘li’ that contains all the valid usernames and corresponding passwords. The first ‘if’ condition is just so that nothing is displayed at the beginning.
Then we check for invalid/valid username, if the username is present in ‘li’ then it is considered as valid, then we check if the password is valid for the given username, and if both of them are correct then boom! You get a link that says ‘Access Granted’ and on clicking the link you can jump to the required page.
In the dcc.Link the first parameter is the text that will be displayed as the link and href is the ‘pathname’ which we have set for a particular page. We will see how these links are defined and how the pathnames are assigned in a while. The rest of the part is just formatting to make it look pretty.
This is the main dash app. Following code is just a basic dash code for explanatory purpose.
Code:
next_page = html.Div([
html.Div(dcc.Link('Log out', href='/',style={'color':'#bed4c4','font-family': 'serif', 'font-weight': 'bold', "text-decoration": "none",'font-size':'20px'}),style={'padding-left':'80%','padding-top':'10px'}),
html.H1(children="This is the Next Page, the main Page",className="ap",style={
'color':'#89b394','text-align':'center','justify':'center','padding-top':'170px','font-weight':'bold',
'font-family':'courier',
'padding-left':'1px' })
])
You can add other components as per your requirement. As you can see I have provided a ‘Logout’ Button at the top right of this page that will take you back to the login page and sign you out. The link is formatted so that it won’t look like a typical blue link with an underline, which makes it look decent.
I have tried to include the maximum required formatting so you don’t have to go look for these little modifications.
The last and the most important part, that is going to handle all the navigation is defining the paths. And here’s how its done.
Code:
@app.callback(dash.dependencies.Output('page-content', 'children'), [dash.dependencies.Input('url', 'pathname')]) def display_page(pathname): if pathname == '/next_page': return next_page else: return index_page
You have to set the pathnames for all the URLs used in the app. I think it’s pretty self-explanatory, you return the respective section for its pathname. The next_page is the Html div component that is defined in the former section.
And of course, run the app.
if __name__=='__main__': app.run_server()
When you run the dash app the dashboard will as follows:
After successful authentication you will get the link that says ‘Access Granted’ as you can see in the image below.
And by clicking on this link you can access your dash app.
Furthermore, you can also add more functionalities like saving the username and password for every new user added and storing these details in the database. By using encryption techniques for storing the password in a database and decrypting for validation. And so on. I will create a blog in the future for this as well. Stay tuned.
I hope this blog explains what I tried to convey and now you can perform testing on the login module for the dash app as well. Thank you! See you in the next one!
Shraddha Shekhar
I am a Computer Engineering student and curious about ML and Data Science. If you like this, do check my other blog.
The media shown in this article are not owned by Analytics Vidhya and is used at the Author’s discretion.
Lorem ipsum dolor sit amet, consectetur adipiscing elit,