mirror of
https://github.com/cesanta/mongoose.git
synced 2025-01-18 23:53:15 +08:00
Add cookie auth example to Mongoose
PUBLISHED_FROM=88bc5059504cfedd078cab277a6d68d1e583fba1
This commit is contained in:
parent
81bf4921d4
commit
69944c1d3a
2
examples/cookie_authentication/Makefile
Normal file
2
examples/cookie_authentication/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
PROG = cookie_auth
|
||||
include ../examples.mk
|
120
examples/cookie_authentication/cookie_auth.c
Normal file
120
examples/cookie_authentication/cookie_auth.c
Normal file
@ -0,0 +1,120 @@
|
||||
// Copyright (c) 2014 Cesanta Software
|
||||
// All rights reserved
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "mongoose.h"
|
||||
|
||||
static const char *s_http_port = "8000";
|
||||
static struct mg_serve_http_opts s_http_server_opts;
|
||||
static const char *s_login_uri = "/login.html";
|
||||
static const char *s_secret = ":-)"; // Must be known only to server
|
||||
|
||||
|
||||
static void generate_ssid(const char *user_name, const char *expiration_date,
|
||||
char *ssid, size_t ssid_size) {
|
||||
char hash[33];
|
||||
cs_md5(hash,
|
||||
user_name, strlen(user_name),
|
||||
":", (size_t) 1,
|
||||
expiration_date, strlen(expiration_date),
|
||||
":", (size_t) 1,
|
||||
s_secret, strlen(s_secret),
|
||||
NULL);
|
||||
snprintf(ssid, ssid_size, "%s|%s|%s", user_name, expiration_date, hash);
|
||||
}
|
||||
|
||||
static int check_auth(struct http_message *hm) {
|
||||
int authenticated = 0;
|
||||
char ssid[100], calculated_ssid[100], name[100], expire[100];
|
||||
|
||||
if (mg_vcmp(&hm->uri, s_login_uri) == 0) {
|
||||
// Always authenticate requests to login page
|
||||
authenticated = 1;
|
||||
} else {
|
||||
// Look for session ID in the Cookie.
|
||||
// That session ID can be validated against the database that stores
|
||||
// current active sessions.
|
||||
mg_http_parse_header(
|
||||
mg_get_http_header(hm, "Cookie"), "ssid", ssid, sizeof(ssid));
|
||||
if (sscanf(ssid, "%[^|]|%[^|]|", name, expire) == 2) {
|
||||
generate_ssid(name, expire, calculated_ssid, sizeof(calculated_ssid));
|
||||
if (strcmp(ssid, calculated_ssid) == 0) {
|
||||
authenticated = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
static void check_login_form_submission(struct mg_connection *c,
|
||||
struct http_message *hm) {
|
||||
char name[100], password[100], ssid[100], expire[100], expire_epoch[100];
|
||||
|
||||
mg_get_http_var(&hm->body, "name", name, sizeof(name));
|
||||
mg_get_http_var(&hm->body, "password", password, sizeof(password));
|
||||
|
||||
// A real authentication mechanism should be employed here.
|
||||
// Also, the whole site should be served through HTTPS.
|
||||
if (strcmp(name, "Joe") == 0 && strcmp(password, "Doe") == 0) {
|
||||
|
||||
// Generate expiry date
|
||||
time_t t = time(NULL) + 3600; // Valid for 1 hour
|
||||
snprintf(expire_epoch, sizeof(expire_epoch), "%lu", (unsigned long) t);
|
||||
strftime(expire, sizeof(expire), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
|
||||
generate_ssid(name, expire_epoch, ssid, sizeof(ssid));
|
||||
|
||||
// Set "session id" cookie, there could be some data encoded in it.
|
||||
mg_printf(c,
|
||||
"HTTP/1.1 302 Moved\r\n"
|
||||
"Set-Cookie: ssid=%s; expire=\"%s\"; http-only; HttpOnly;\r\n"
|
||||
"Location: /\r\n\r\n",
|
||||
ssid, expire);
|
||||
} else {
|
||||
mg_printf(c, "%s", "HTTP/1.1 302 Moved\r\nLocation: /\r\n\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_REQUEST) {
|
||||
struct http_message *hm = (struct http_message *) ev_data;
|
||||
|
||||
if (mg_vcmp(&hm->uri, s_login_uri) == 0 &&
|
||||
mg_vcmp(&hm->method, "POST") == 0) {
|
||||
check_login_form_submission(c, hm);
|
||||
} else if (check_auth(hm)) {
|
||||
// Authenticated. Serve files.
|
||||
mg_serve_http(c, (struct http_message *) ev_data, s_http_server_opts);
|
||||
} else {
|
||||
// Not authenticated. Redirect to the login page.
|
||||
mg_printf(c, "HTTP/1.1 302 Moved\r\nLocation: %s\r\n\r\n", s_login_uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
struct mg_connection *c;
|
||||
|
||||
mg_mgr_init(&mgr, NULL);
|
||||
c = mg_bind(&mgr, s_http_port, ev_handler);
|
||||
|
||||
if (c == NULL) {
|
||||
printf("Cannot start server on port %s\n", s_http_port);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Set up HTTP server parameters
|
||||
mg_set_protocol_http_websocket(c);
|
||||
s_http_server_opts.document_root = "."; // Serve current directory
|
||||
|
||||
printf("Starting web server on port %s\n", s_http_port);
|
||||
for (;;) {
|
||||
mg_mgr_poll(&mgr, 1000);
|
||||
}
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return 0;
|
||||
}
|
33
examples/cookie_authentication/index.html
Normal file
33
examples/cookie_authentication/index.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>WebSocket Test</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
background-color: #cde; margin: 0;
|
||||
padding: 0; font: 14px Helvetica, Arial, sans-serif;
|
||||
}
|
||||
* { outline: none; }
|
||||
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.4em; margin: 0 0 10px 0; }
|
||||
a:link, a:visited { color: #69c; text-decoration: none; }
|
||||
@media (max-width: 700px) {
|
||||
body { background-color: #fff; }
|
||||
div.content {
|
||||
width: auto; margin: 0 auto; border-radius: 0; padding: 1em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1>Mongoose Cookie Base Authentication</h1>
|
||||
<p>This is an index page. Authentication succeeded.</p>
|
||||
</body>
|
||||
</html>
|
44
examples/cookie_authentication/login.html
Normal file
44
examples/cookie_authentication/login.html
Normal file
@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>WebSocket Test</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
background-color: #cde; margin: 0;
|
||||
padding: 0; font: 14px Helvetica, Arial, sans-serif;
|
||||
}
|
||||
* { outline: none; }
|
||||
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.4em; margin: 0 0 10px 0; }
|
||||
a:link, a:visited { color: #69c; text-decoration: none; }
|
||||
@media (max-width: 700px) {
|
||||
body { background-color: #fff; }
|
||||
div.content {
|
||||
width: auto; margin: 0 auto; border-radius: 0; padding: 1em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1>Mongoose Cookie Based Authentication</h1>
|
||||
<p>Use name "Joe", password "Doe" to login.</p>
|
||||
<form method="POST">
|
||||
<div>
|
||||
<label>Name:</label>
|
||||
<input type="text" name="name"/>
|
||||
</div><div>
|
||||
<label>Password:</label>
|
||||
<input type="password" name="password"/>
|
||||
</div><div>
|
||||
<input type="submit" value="Login"/>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user