Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
M
mongoose
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
mongoose
Commits
6572c1c6
Commit
6572c1c6
authored
Aug 08, 2016
by
Deomid Ryabkov
Committed by
Cesanta Bot
Aug 08, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add a cookie auth and session management example
PUBLISHED_FROM=243437cf7d48b04aef3896bc4c5d4010975299a4
parent
7b48859f
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
299 additions
and
0 deletions
+299
-0
Makefile
examples/cookie_auth/Makefile
+2
-0
cookie_auth.c
examples/cookie_auth/cookie_auth.c
+254
-0
login.html
examples/cookie_auth/login.html
+43
-0
No files found.
examples/cookie_auth/Makefile
0 → 100644
View file @
6572c1c6
PROG
=
cookie_auth
include
../examples.mk
examples/cookie_auth/cookie_auth.c
0 → 100644
View file @
6572c1c6
/*
* Copyright (c) 2016 Cesanta Software Limited
* All rights reserved
*
* This example demonstrates how to implement cookie authentication
* and session management using Mongoose.
*/
#include <inttypes.h>
#include <stdlib.h>
#include "mongoose.h"
static
const
char
*
s_http_port
=
"8000"
;
static
struct
mg_serve_http_opts
s_http_server_opts
;
/* This is the name of the cookie carrying the session ID. */
#define SESSION_COOKIE_NAME "mgs"
/* In our example sessions are destroyed after 30 seconds of inactivity. */
#define SESSION_TTL 30.0
#define SESSION_CHECK_INTERVAL 5.0
/* Session information structure. */
struct
session
{
/* Session ID. Must be unique and hard to guess. */
uint64_t
id
;
/*
* Time when the session was created and time of last activity.
* Used to clean up stale sessions.
*/
double
created
;
double
last_used
;
/* Time when the session was last active. */
/* User name this session is associated with. */
char
*
user
;
/* Some state associated with user's session. */
int
lucky_number
;
};
/*
* This example uses a simple in-memory storage for just 10 sessions.
* A real-world implementation would use persistent storage of some sort.
*/
#define NUM_SESSIONS 10
struct
session
s_sessions
[
NUM_SESSIONS
];
/*
* Password check function.
* In our example all users have password "password".
*/
static
int
check_pass
(
const
char
*
user
,
const
char
*
pass
)
{
(
void
)
user
;
return
(
strcmp
(
pass
,
"password"
)
==
0
);
}
/*
* Parses the session cookie and returns a pointer to the session struct
* or NULL if not found.
*/
static
struct
session
*
get_session
(
struct
http_message
*
hm
)
{
struct
mg_str
*
cookie_header
=
mg_get_http_header
(
hm
,
"cookie"
);
if
(
cookie_header
==
NULL
)
return
NULL
;
char
ssid
[
21
];
if
(
!
mg_http_parse_header
(
cookie_header
,
SESSION_COOKIE_NAME
,
ssid
,
sizeof
(
ssid
)))
{
return
NULL
;
}
uint64_t
sid
=
strtoull
(
ssid
,
NULL
,
16
);
for
(
int
i
=
0
;
i
<
NUM_SESSIONS
;
i
++
)
{
if
(
s_sessions
[
i
].
id
==
sid
)
{
s_sessions
[
i
].
last_used
=
mg_time
();
return
&
s_sessions
[
i
];
}
}
return
NULL
;
}
/*
* Destroys the session state.
*/
static
void
destroy_session
(
struct
session
*
s
)
{
free
(
s
->
user
);
memset
(
s
,
0
,
sizeof
(
*
s
));
}
/*
* Creates a new session for the user.
*/
static
struct
session
*
create_session
(
const
char
*
user
,
const
struct
http_message
*
hm
)
{
/* Find first available slot or use the oldest one. */
struct
session
*
s
=
NULL
;
struct
session
*
oldest_s
=
s_sessions
;
for
(
int
i
=
0
;
i
<
NUM_SESSIONS
;
i
++
)
{
if
(
s_sessions
[
i
].
id
==
0
)
{
s
=
&
s_sessions
[
i
];
break
;
}
if
(
s_sessions
[
i
].
last_used
<
oldest_s
->
last_used
)
{
oldest_s
=
&
s_sessions
[
i
];
}
}
if
(
s
==
NULL
)
{
destroy_session
(
oldest_s
);
printf
(
"Evicted %"
INT64_X_FMT
"/%s
\n
"
,
oldest_s
->
id
,
oldest_s
->
user
);
s
=
oldest_s
;
}
/* Initialize new session. */
s
->
created
=
s
->
last_used
=
mg_time
();
s
->
user
=
strdup
(
user
);
s
->
lucky_number
=
rand
();
/* Create an ID by putting various volatiles into a pot and stirring. */
cs_sha1_ctx
ctx
;
cs_sha1_init
(
&
ctx
);
cs_sha1_update
(
&
ctx
,
(
const
unsigned
char
*
)
hm
->
message
.
p
,
hm
->
message
.
len
);
cs_sha1_update
(
&
ctx
,
(
const
unsigned
char
*
)
s
,
sizeof
(
*
s
));
unsigned
char
digest
[
20
];
cs_sha1_final
(
digest
,
&
ctx
);
s
->
id
=
*
((
uint64_t
*
)
digest
);
return
s
;
}
static
void
set_session_cookie
(
struct
mg_connection
*
nc
,
const
struct
session
*
s
)
{
mg_printf
(
nc
,
"Set-Cookie: %s=%"
INT64_X_FMT
"; path=/
\r\n
"
,
SESSION_COOKIE_NAME
,
s
->
id
);
}
/*
* If requested via GET, serves the login page.
* If requested via POST (form submission), checks password and logs user in.
*/
static
void
login_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
p
)
{
struct
http_message
*
hm
=
(
struct
http_message
*
)
p
;
if
(
mg_vcmp
(
&
hm
->
method
,
"POST"
)
!=
0
)
{
/* Serve login.html */
mg_serve_http
(
nc
,
(
struct
http_message
*
)
p
,
s_http_server_opts
);
}
else
{
/* Perform password check. */
char
user
[
50
],
pass
[
50
];
int
ul
=
mg_get_http_var
(
&
hm
->
body
,
"user"
,
user
,
sizeof
(
user
));
int
pl
=
mg_get_http_var
(
&
hm
->
body
,
"pass"
,
pass
,
sizeof
(
pass
));
if
(
ul
>
0
&&
pl
>
0
)
{
if
(
check_pass
(
user
,
pass
))
{
struct
session
*
s
=
create_session
(
user
,
hm
);
mg_printf
(
nc
,
"HTTP/1.0 302 Found
\r\n
"
);
set_session_cookie
(
nc
,
s
);
mg_printf
(
nc
,
"Location: /
\r\n
"
);
mg_printf
(
nc
,
"
\r\n
Hello, %s!
\r\n
"
,
s
->
user
);
fprintf
(
stderr
,
"%s logged in, sid %"
INT64_X_FMT
"
\n
"
,
s
->
user
,
s
->
id
);
}
else
{
mg_printf
(
nc
,
"HTTP/1.0 403 Unauthorized
\r\n\r\n
Wrong password.
\r\n
"
);
}
}
else
{
mg_printf
(
nc
,
"HTTP/1.0 400 Bad Request
\r\n\r\n
user, pass required.
\r\n
"
);
}
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
}
(
void
)
ev
;
}
/*
* Logs the user out.
* Removes cookie and any associated session state.
*/
static
void
logout_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
p
)
{
struct
http_message
*
hm
=
(
struct
http_message
*
)
p
;
mg_printf
(
nc
,
"HTTP/1.0 302 Found
\r\n
"
"Set-Cookie: %s=
\r\n
"
"Location: /
\r\n
"
"
\r\n
"
"Logged out"
,
SESSION_COOKIE_NAME
);
struct
session
*
s
=
get_session
(
hm
);
if
(
s
!=
NULL
)
{
fprintf
(
stderr
,
"%s logged out, session %"
INT64_X_FMT
" destroyed
\n
"
,
s
->
user
,
s
->
id
);
destroy_session
(
s
);
}
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
(
void
)
ev
;
}
/* Cleans up sessions that have been idle for too long. */
void
check_sessions
()
{
double
threshold
=
mg_time
()
-
SESSION_TTL
;
for
(
int
i
=
0
;
i
<
NUM_SESSIONS
;
i
++
)
{
struct
session
*
s
=
&
s_sessions
[
i
];
if
(
s
->
id
!=
0
&&
s
->
last_used
<
threshold
)
{
fprintf
(
stderr
,
"Session %"
INT64_X_FMT
" (%s) closed due to idleness.
\n
"
,
s
->
id
,
s
->
user
);
destroy_session
(
s
);
}
}
}
/* Main event handler. */
static
void
ev_handler
(
struct
mg_connection
*
nc
,
int
ev
,
void
*
p
)
{
/* Perform session maintenance. */
if
(
ev
==
MG_EV_TIMER
)
{
check_sessions
();
mg_set_timer
(
nc
,
mg_time
()
+
SESSION_CHECK_INTERVAL
);
return
;
}
if
(
ev
!=
MG_EV_HTTP_REQUEST
)
return
;
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
struct
http_message
*
hm
=
(
struct
http_message
*
)
p
;
struct
session
*
s
=
get_session
(
hm
);
/* Ask the user to log in if they did not present a valid cookie. */
if
(
s
==
NULL
)
{
mg_printf
(
nc
,
"HTTP/1.0 302 Found
\r\n
"
"Location: /login.html
\r\n
"
"
\r\n
"
"Please log in"
);
return
;
}
/* Application logic that uses session data goes here. */
fprintf
(
stderr
,
"%s (sid %"
INT64_X_FMT
") requested %.*s
\n
"
,
s
->
user
,
s
->
id
,
(
int
)
hm
->
uri
.
len
,
hm
->
uri
.
p
);
mg_printf
(
nc
,
"HTTP/1.0 200 Ok
\r\n
"
"COntent-Type: text/html
\r\n
"
"
\r\n
"
"<h1>Hello, %s!</h1>
\r\n
"
"<p>Your lucky number is %d.</p>
\r\n
"
"<p><a href=/logout>Log out</a>"
,
s
->
user
,
s
->
lucky_number
);
}
int
main
(
void
)
{
struct
mg_mgr
mgr
;
struct
mg_connection
*
nc
;
srand
(
mg_time
());
mg_mgr_init
(
&
mgr
,
NULL
);
nc
=
mg_bind
(
&
mgr
,
s_http_port
,
ev_handler
);
mg_set_protocol_http_websocket
(
nc
);
s_http_server_opts
.
document_root
=
"."
;
mg_register_http_endpoint
(
nc
,
"/login.html"
,
login_handler
);
mg_register_http_endpoint
(
nc
,
"/logout"
,
logout_handler
);
mg_set_timer
(
nc
,
mg_time
()
+
SESSION_CHECK_INTERVAL
);
printf
(
"Starting web server on port %s
\n
"
,
s_http_port
);
for
(;;)
{
mg_mgr_poll
(
&
mgr
,
1000
);
}
mg_mgr_free
(
&
mgr
);
return
0
;
}
examples/cookie_auth/login.html
0 → 100644
View file @
6572c1c6
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"utf-8"
/>
<title>
Please log in
</title>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1"
/>
<style
type=
"text/css"
>
*
{
outline
:
none
;
}
body
{
background-color
:
#789
;
margin
:
0
;
padding
:
0
;
font
:
16px
/
1.4
Helvetica
,
Arial
,
sans-serif
;
font
:
16px
/
1.4
Helvetica
,
Arial
,
sans-serif
;
}
div
.content
{
width
:
800px
;
margin
:
2em
auto
;
padding
:
20px
50px
;
background-color
:
#fff
;
border-radius
:
1em
;
}
label
{
display
:
inline-block
;
min-width
:
7em
;
}
input
{
border
:
1px
solid
#ccc
;
padding
:
0.2em
;
}
a
:link
,
a
:visited
{
color
:
#69c
;
text-decoration
:
none
;
}
@media
(
max-width
:
700px
)
{
body
{
background-color
:
#fff
;
}
div
.content
{
width
:
auto
;
margin
:
0
auto
;
padding
:
1em
;
}
}
</style>
</head>
<body>
<div
class=
"content"
>
<h1>
Please log in
</h1>
<form
method=
"POST"
>
<div>
<label>
Username:
</label>
<input
type=
"text"
name=
"user"
/>
</div>
<div>
<label>
Password:
</label>
<input
type=
"password"
name=
"pass"
/>
</div>
<div>
<input
type=
"submit"
value=
"Log in"
>
</div>
</form>
</div>
</body>
</html>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment