Concepts of modular tonton web application that share authentication
This commit is contained in:
parent
7fe8986bdb
commit
eb759a8454
7 changed files with 192 additions and 75 deletions
6
Gemfile
6
Gemfile
|
|
@ -4,4 +4,8 @@ gem 'sinatra'
|
||||||
gem 'liquid'
|
gem 'liquid'
|
||||||
gem 'sinatra-flash'
|
gem 'sinatra-flash'
|
||||||
gem 'puma'
|
gem 'puma'
|
||||||
gem 'sod'
|
gem 'sod'
|
||||||
|
gem 'gollum'
|
||||||
|
gem 'bcrypt'
|
||||||
|
gem 'sqlite3'
|
||||||
|
gem 'warden'
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
require_relative 'app'
|
require_relative 'example/app'
|
||||||
|
require_relative 'example/modules/module'
|
||||||
|
|
||||||
# Require TonTon modules if you want
|
# Require TonTon modules if you want
|
||||||
|
|
||||||
use Rack::Session::Cookie, key: 'rack.session', secret: ENV.fetch('SESSION_SECRET')
|
use Rack::Session::Cookie, key: 'rack.session', secret: ENV.fetch('SESSION_SECRET')
|
||||||
|
|
||||||
app = Rack::URLMap.new(
|
app = Rack::URLMap.new(
|
||||||
'/' => TonTonWeb::App.new
|
'/' => ExampleApp.new,
|
||||||
# Add TonTon modules here
|
'/module' => ExampleModule.new
|
||||||
)
|
)
|
||||||
|
|
||||||
run app
|
run app
|
||||||
|
|
@ -1,18 +1,5 @@
|
||||||
require 'gollum/app'
|
require_relative '../lib/tonton_web'
|
||||||
require 'sinatra/flash'
|
|
||||||
require "sqlite3"
|
|
||||||
require 'tonton_web'
|
|
||||||
|
|
||||||
class TonTonWeb::App < Sinatra::Base
|
class ExampleApp < TonTonWeb::App
|
||||||
set :host_authorization, { permitted_hosts: ['localhost', 'mytonton.com.br'] }
|
set :root, Pathname.new(__FILE__).parent.parent
|
||||||
|
|
||||||
set :sessions, true
|
|
||||||
|
|
||||||
get '/' do
|
|
||||||
redirect "/readme.md"
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/:name' do
|
|
||||||
markdown File.read(params['name']), layout_engine: :erb, layout: true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
@ -1 +1,4 @@
|
||||||
require_relative 'tonton_web/auth'
|
require_relative 'tonton_web/auth'
|
||||||
|
require_relative 'tonton_web/sinatra-auth'
|
||||||
|
require_relative 'tonton_web/app'
|
||||||
|
require_relative 'tonton_web/module'
|
||||||
109
lib/tonton_web/app.rb
Normal file
109
lib/tonton_web/app.rb
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
require_relative 'auth'
|
||||||
|
require "warden"
|
||||||
|
require 'sinatra/flash'
|
||||||
|
|
||||||
|
Warden::Manager.serialize_from_session do |id|
|
||||||
|
TonTonWeb::App.find_user id: id
|
||||||
|
end
|
||||||
|
|
||||||
|
Warden::Manager.serialize_into_session do |user|
|
||||||
|
user.id
|
||||||
|
end
|
||||||
|
|
||||||
|
Warden::Manager.before_failure do |env,opts|
|
||||||
|
env['REQUEST_METHOD'] = "POST"
|
||||||
|
|
||||||
|
env['rack.session']['warden.options'] = opts
|
||||||
|
end
|
||||||
|
|
||||||
|
Warden::Strategies.add(:password) do
|
||||||
|
def valid?
|
||||||
|
params['user'] && params['user']['username'] && params['user']['password']
|
||||||
|
end
|
||||||
|
|
||||||
|
def authenticate!
|
||||||
|
user_params = params['user']
|
||||||
|
|
||||||
|
user = TonTonWeb::App.authenticate user_params['username'], user_params['password']
|
||||||
|
|
||||||
|
if not user
|
||||||
|
throw(:warden)
|
||||||
|
else
|
||||||
|
success!(user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TonTonWeb::App < Sinatra::Base
|
||||||
|
@db = SQLite3::Database.new(Dir.getwd + '/database.sqlite')
|
||||||
|
|
||||||
|
register Sinatra::Flash
|
||||||
|
register TonTonWeb::Auth
|
||||||
|
|
||||||
|
use Warden::Manager do |manager|
|
||||||
|
manager.default_strategies :password
|
||||||
|
|
||||||
|
manager.failure_app = self
|
||||||
|
|
||||||
|
manager.scope_defaults :default, strategies: [:password], action: 'unauthenticated'
|
||||||
|
end
|
||||||
|
|
||||||
|
helpers do
|
||||||
|
def check_authentication
|
||||||
|
if not env['warden'].authenticated?
|
||||||
|
flash[:error] = 'You must log in to access this page.'
|
||||||
|
|
||||||
|
redirect '/login'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_user
|
||||||
|
env['warden'].user
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
set :host_authorization, { permitted_hosts: ['localhost', 'mytonton.com.br'] }
|
||||||
|
|
||||||
|
get '/' do
|
||||||
|
redirect "/readme.md"
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/status' do
|
||||||
|
puts env['warden']
|
||||||
|
check_authentication
|
||||||
|
"Hello"
|
||||||
|
end
|
||||||
|
|
||||||
|
post '/unauthenticated' do
|
||||||
|
session['warden.return_to'] = env['warden.options'][:attempted_path]
|
||||||
|
|
||||||
|
flash[:error] = 'You must log in to access this page.'
|
||||||
|
|
||||||
|
redirect '/login'
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/login' do
|
||||||
|
@error = flash[:error]
|
||||||
|
|
||||||
|
erb :login
|
||||||
|
end
|
||||||
|
|
||||||
|
post '/login' do
|
||||||
|
env['warden'].authenticate!
|
||||||
|
|
||||||
|
if env['warden'].authenticated?
|
||||||
|
redirect_path = session.delete('warden.return_to') || '/'
|
||||||
|
|
||||||
|
redirect redirect_path
|
||||||
|
else
|
||||||
|
redirect '/login'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/logout' do
|
||||||
|
env['warden'].logout
|
||||||
|
|
||||||
|
redirect '/'
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
@ -4,70 +4,63 @@ require 'bcrypt'
|
||||||
|
|
||||||
module TonTonWeb
|
module TonTonWeb
|
||||||
User = Struct.new(:id, :name, :username, :email, :password_digest)
|
User = Struct.new(:id, :name, :username, :email, :password_digest)
|
||||||
|
end
|
||||||
|
|
||||||
class Auth
|
module TonTonWeb::Auth
|
||||||
attr_reader :root
|
def create_tables
|
||||||
|
@db.execute "create table users (id integer primary key, name text, username text, email text, password_digest text);"
|
||||||
|
end
|
||||||
|
|
||||||
def initialize root_path
|
def create_user **options
|
||||||
@root = Pathname.new root_path
|
name = options.fetch :name
|
||||||
|
username = options.fetch :username
|
||||||
|
email = options.fetch :email
|
||||||
|
password = options.fetch :password
|
||||||
|
|
||||||
@db = SQLite3::Database.new(@root+ 'database.sqlite')
|
# Assert user doesn't exists
|
||||||
|
|
||||||
|
hashed_password = BCrypt::Password.create(password)
|
||||||
|
|
||||||
|
@db.execute(
|
||||||
|
"insert into users (name, username, email, password_digest) values (?,?,?,?);",
|
||||||
|
[name, username, email, hashed_password]
|
||||||
|
)
|
||||||
|
|
||||||
|
return # Return user
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_user id
|
||||||
|
@db.execute "delete from users where id = ?;", id
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_user **options
|
||||||
|
id = options[:id]
|
||||||
|
name = options[:name]
|
||||||
|
username = options[:username]
|
||||||
|
email = options[:email]
|
||||||
|
|
||||||
|
if not (id or name or username or email)
|
||||||
|
raise "No options to find user."
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_tables
|
user = nil
|
||||||
@db.execute "create table users (id integer primary key, name text, username text, email text, password_digest text);"
|
|
||||||
|
user_query_template = "select id, name, username, email, password_digest from users where id = ? or name = ? or username = ? or email = ?"
|
||||||
|
|
||||||
|
@db.execute(user_query_template, [id, name, username, email]) do |row|
|
||||||
|
user = TonTonWeb::User.new(*row)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_user **options
|
return user
|
||||||
name = options.fetch :name
|
end
|
||||||
username = options.fetch :username
|
|
||||||
email = options.fetch :email
|
|
||||||
password = options.fetch :password
|
|
||||||
|
|
||||||
# Assert user doesn't exists
|
def authenticate username, password
|
||||||
|
user = find_user(username: username)
|
||||||
hashed_password = BCrypt::Password.create(password)
|
|
||||||
|
|
||||||
@db.execute(
|
|
||||||
"insert into users (name, username, email, password_digest) values (?,?,?,?);",
|
|
||||||
[name, username, email, password]
|
|
||||||
)
|
|
||||||
|
|
||||||
return # Return user
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete_user id
|
|
||||||
@db.execute "delete from users where id = ?;", id
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_user **options
|
|
||||||
name = options[:name]
|
|
||||||
username = options[:username]
|
|
||||||
email = options[:email]
|
|
||||||
|
|
||||||
if not (name or username or email)
|
|
||||||
raise "No options to find user."
|
|
||||||
end
|
|
||||||
|
|
||||||
user = nil
|
|
||||||
|
|
||||||
user_query_template = "select id, name, username, email, password_digest from users where name = ? or username = ? or email = ?"
|
|
||||||
|
|
||||||
@db.execute(user_query_template, [name, username, email]) do |row|
|
|
||||||
user = TonTonWeb::User.new(*row)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
if BCrypt::Password.new(user.password_digest) == password
|
||||||
return user
|
return user
|
||||||
end
|
else
|
||||||
|
return false
|
||||||
def authenticate username, password
|
|
||||||
user = find_user(username: username)
|
|
||||||
|
|
||||||
if BCrypt::Password.new(user.password_digest) == password
|
|
||||||
return user
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
20
views/login.erb
Normal file
20
views/login.erb
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<h2>Login</h2>
|
||||||
|
<% if @error %>
|
||||||
|
<p style="color: red; font-weight: bold;">
|
||||||
|
<%= @error %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<form method="POST" action="/login">
|
||||||
|
<div>
|
||||||
|
<label for="username">Username:</label>
|
||||||
|
<input type="text" id="username" name="user[username]" required>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div>
|
||||||
|
<label for="password">Password:</label>
|
||||||
|
<input type="password" id="password" name="user[password]" required>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<button type="submit">Log In</button>
|
||||||
|
</form>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue