-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathapp.rb
146 lines (111 loc) · 3.38 KB
/
app.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
require 'rubygems'
require 'bundler/setup'
require 'sinatra'
require 'openssl'
require 'jwt'
######
# first we load up the private and public keys that we will use to sign and verify our JWT token
# using RS256 algo
######
signing_key_path = File.expand_path("../app.rsa", __FILE__)
verify_key_path = File.expand_path("../app.rsa.pub", __FILE__)
signing_key = ""
verify_key = ""
File.open(signing_key_path) do |file|
signing_key = OpenSSL::PKey.read(file)
end
File.open(verify_key_path) do |file|
verify_key = OpenSSL::PKey.read(file)
end
set :signing_key, signing_key
set :verify_key, verify_key
# enable sessions which will be our default for storing the token
enable :sessions
#this is to encrypt the session, but not really necessary just for token because we aren't putting any sensitive info in there
set :session_secret, 'super secret 2'
helpers do
# protected just does a redirect if we don't have a valid token
def protected!
return if authorized?
redirect to('/login')
end
# helper to extract the token from the session, header or request param
# if we are building an api, we would obviously want to handle header or request param
def extract_token
# check for the access_token header
token = request.env["access_token"]
if token
return token
end
# or the form parameter _access_token
token = request["access_token"]
if token
return token
end
# or check the session for the access_token
token = session["access_token"]
if token
return token
end
return nil
end
# check the token to make sure it is valid with our public key
def authorized?
@token = extract_token
if @token.nil?
session["message"] = "No JWT found in session. Please log in."
return false
end
begin
@payload, @header = JWT.decode(@token, settings.verify_key, true, { algorithm: 'RS256'} )
@exp = @header["exp"]
# check to see if the exp is set (we don't accept forever tokens)
if @exp.nil?
session["message"] = "No exp set on JWT token."
return false
end
@exp = Time.at(@exp.to_i)
# make sure the token hasn't expired
if Time.now > @exp
session["message"] = "JWT token expired."
return false
end
@user_id = @payload["user_id"]
rescue JWT::DecodeError => e
session["message"] = "JWT decode error: #{e.message}"
return false
end
end
end
get '/' do
protected!
erb :index
end
get '/login' do
@message = session["message"]
session.delete("message")
erb :login
end
get '/logout' do
session["access_token"] = nil
redirect to("/")
end
post '/login' do
# check the username and password
# you would use some sort of User record here to verify the credentials
if params[:username] == "username" && params[:password] == "password"
# if the user/pass credentials are valid, lets issue a JSON Web Token:
# normally you might put the user_id in payload, or some other identifying
# attributes that we can use to get the current authenticated user's identity
# on future visists to the site
headers = {
exp: Time.now.to_i + 20 #expire in 20 seconds
}
@token = JWT.encode({user_id: 123456}, settings.signing_key, "RS256", headers)
session["access_token"] = @token
redirect to("/")
else
@message = "Username/Password failed."
erb :login
end
end