Browse Source

Basic login

Maarten van den Berg 8 years ago
parent
commit
13a07c2612

+ 2 - 0
app/controllers/application_controller.rb

2
   protect_from_forgery with: :exception
2
   protect_from_forgery with: :exception
3
   rescue_from ActionController::InvalidAuthenticityToken, with: :invalid_auth_token
3
   rescue_from ActionController::InvalidAuthenticityToken, with: :invalid_auth_token
4
 
4
 
5
+  include AuthenticationHelper
6
+
5
   private
7
   private
6
   def invalid_auth_token
8
   def invalid_auth_token
7
     render text: "You submitted an invalid request! If you got here after clicking a link, it's possible that someone is doing something nasty!", status: 400
9
     render text: "You submitted an invalid request! If you got here after clicking a link, it's possible that someone is doing something nasty!", status: 400

+ 11 - 1
app/controllers/authentication_controller.rb

10
       u = User.find_by(email: params[:session][:email])
10
       u = User.find_by(email: params[:session][:email])
11
 
11
 
12
       if u && u.authenticate(params[:session][:password])
12
       if u && u.authenticate(params[:session][:password])
13
-        # TODO Login logic here
13
+        log_in(u, params[:session][:remember_me].to_i)
14
+
14
         flash[:success] = "Hello, #{u.person.full_name}!"
15
         flash[:success] = "Hello, #{u.person.full_name}!"
15
       else
16
       else
16
         flash[:danger] = "Invalid username/password combination!"
17
         flash[:danger] = "Invalid username/password combination!"
24
     render layout: 'void'
25
     render layout: 'void'
25
   end
26
   end
26
 
27
 
28
+  def login_status
29
+    render text: is_logged_in?
30
+  end
31
+
27
   def create_password
32
   def create_password
28
     flash[:danger] = "Not yet implemented."
33
     flash[:danger] = "Not yet implemented."
29
     redirect_to action: 'login'
34
     redirect_to action: 'login'
37
     flash[:danger] = "Not yet implemented."
42
     flash[:danger] = "Not yet implemented."
38
     redirect_to action: 'login'
43
     redirect_to action: 'login'
39
   end
44
   end
45
+
46
+  private
47
+  def session_params
48
+    params.require(:session).permit(:email, :password, :remember_me)
49
+  end
40
 end
50
 end

+ 62 - 0
app/helpers/authentication_helper.rb

1
 module AuthenticationHelper
1
 module AuthenticationHelper
2
+  def log_in(user, remember, new=true)
3
+    reset_session
4
+
5
+    expiry = 6.hours.since
6
+    session[:user_id] = user.id
7
+    session[:expires] = expiry
8
+
9
+    if new
10
+      if remember == 1
11
+        token = Session.new_token
12
+        cookies.signed.permanent[:remember_token] = token
13
+        cookies.signed.permanent[:user_id] = user.id
14
+      else
15
+        token = nil
16
+      end
17
+      s = Session.create!(
18
+        user: user,
19
+        ip: request.remote_ip,
20
+        expires: expiry,
21
+        remember_digest: token ? Session.digest(token) : nil
22
+      )
23
+      if remember
24
+        cookies.signed.permanent[:session_id] = s.id
25
+      end
26
+    end
27
+  end
28
+
29
+  def is_logged_in?
30
+    # Case 1: User has an active session inside the cookie.
31
+    # We verify that the session hasn't expired yet.
32
+    if session[:user_id] && session[:expires].to_time > DateTime.now
33
+
34
+      return true
35
+
36
+    else
37
+      # Case 2: User is returning and has a remember token saved.
38
+      # We get the Session, check the token and expiry, and log the user in.
39
+      if cookies.signed.permanent[:remember_token] && cookies.signed.permanent[:user_id] &&
40
+          cookies.signed.permanent[:session_id]
41
+
42
+        s = Session.find_by(
43
+          id: cookies.signed.permanent[:session_id]
44
+        )
45
+        if s.nil? || s.remember_digest.nil?
46
+          return false
47
+        end
48
+
49
+        session_password = BCrypt::Password.new s.remember_digest
50
+
51
+        if s.expires > DateTime.now && session_password == cookies.signed.permanent[:remember_token]
52
+          log_in s.user, false, false
53
+          return true
54
+        end
55
+
56
+      return false
57
+      end
58
+
59
+    return false
60
+
61
+    end
62
+  end
63
+
2
 end
64
 end

+ 13 - 0
app/models/session.rb

1
+class Session < ApplicationRecord
2
+  belongs_to :user
3
+
4
+  def Session.new_token
5
+    SecureRandom.urlsafe_base64
6
+  end
7
+
8
+  def Session.digest(string)
9
+    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
10
+                                                  BCrypt::Engine.cost
11
+    BCrypt::Password.create(string, cost: cost)
12
+  end
13
+end

+ 2 - 0
config/routes.rb

8
   get  'forgot', to: 'authentication#forgotten_password_form'
8
   get  'forgot', to: 'authentication#forgotten_password_form'
9
   post 'forgot', to: 'authentication#forgotten_password'
9
   post 'forgot', to: 'authentication#forgotten_password'
10
 
10
 
11
+  get 'logintest', to: 'authentication#login_status'
12
+
11
   # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
13
   # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
12
 end
14
 end

+ 13 - 0
db/migrate/20161212211342_create_sessions.rb

1
+class CreateSessions < ActiveRecord::Migration[5.0]
2
+  def change
3
+    create_table :sessions do |t|
4
+      t.string :ip
5
+      t.datetime :expires
6
+      t.string :remember_digest, unique: true
7
+      t.references :user, foreign_key: true
8
+      t.boolean :active, default: true
9
+
10
+      t.timestamps
11
+    end
12
+  end
13
+end

+ 12 - 1
db/schema.rb

10
 #
10
 #
11
 # It's strongly recommended that you check this file into your version control system.
11
 # It's strongly recommended that you check this file into your version control system.
12
 
12
 
13
-ActiveRecord::Schema.define(version: 20161208092632) do
13
+ActiveRecord::Schema.define(version: 20161212211342) do
14
 
14
 
15
   create_table "activities", force: :cascade do |t|
15
   create_table "activities", force: :cascade do |t|
16
     t.string   "public_name"
16
     t.string   "public_name"
68
     t.index ["email"], name: "index_people_on_email", unique: true
68
     t.index ["email"], name: "index_people_on_email", unique: true
69
   end
69
   end
70
 
70
 
71
+  create_table "sessions", force: :cascade do |t|
72
+    t.string   "ip"
73
+    t.datetime "expires"
74
+    t.string   "remember_digest"
75
+    t.integer  "user_id"
76
+    t.boolean  "active",          default: true
77
+    t.datetime "created_at",                     null: false
78
+    t.datetime "updated_at",                     null: false
79
+    t.index ["user_id"], name: "index_sessions_on_user_id"
80
+  end
81
+
71
   create_table "users", force: :cascade do |t|
82
   create_table "users", force: :cascade do |t|
72
     t.string   "email"
83
     t.string   "email"
73
     t.string   "password_digest"
84
     t.string   "password_digest"

+ 15 - 0
test/fixtures/sessions.yml

1
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2
+
3
+one:
4
+  ip: MyString
5
+  expires: 2016-12-12 22:13:42
6
+  remember_digest: MyString
7
+  user: one
8
+  active: 
9
+
10
+two:
11
+  ip: MyString
12
+  expires: 2016-12-12 22:13:42
13
+  remember_digest: MyString
14
+  user: two
15
+  active: 

+ 7 - 0
test/models/session_test.rb

1
+require 'test_helper'
2
+
3
+class SessionTest < ActiveSupport::TestCase
4
+  # test "the truth" do
5
+  #   assert true
6
+  # end
7
+end