Dan Brown

Added social sign in

......@@ -22,8 +22,7 @@ class Handler extends ExceptionHandler
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
* @return void
* @param \Exception $e
*/
public function report(Exception $e)
{
......@@ -39,6 +38,11 @@ class Handler extends ExceptionHandler
*/
public function render($request, Exception $e)
{
if($e instanceof NotifyException) {
\Session::flash('error', $e->message);
return response()->redirectTo($e->redirectLocation);
}
return parent::render($request, $e);
}
}
......
<?php namespace Oxbow\Exceptions;
class NotifyException extends \Exception
{
public $message;
public $redirectLocation;
/**
* NotifyException constructor.
* @param string $message
* @param string $redirectLocation
*/
public function __construct($message, $redirectLocation)
{
$this->message = $message;
$this->redirectLocation = $redirectLocation;
parent::__construct();
}
}
\ No newline at end of file
<?php namespace Oxbow\Exceptions;
class SocialDriverNotConfigured extends \Exception
{
}
\ No newline at end of file
<?php namespace Oxbow\Exceptions;
class UserNotFound extends NotifyException
{
}
\ No newline at end of file
......@@ -2,11 +2,15 @@
namespace Oxbow\Http\Controllers\Auth;
use Oxbow\Exceptions\SocialDriverNotConfigured;
use Oxbow\Exceptions\UserNotFound;
use Oxbow\Repos\UserRepo;
use Oxbow\User;
use Validator;
use Oxbow\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Laravel\Socialite\Contracts\Factory as Socialite;
class AuthController extends Controller
{
......@@ -27,28 +31,34 @@ class AuthController extends Controller
protected $redirectPath = '/';
protected $redirectAfterLogout = '/login';
protected $validSocialDrivers = ['google', 'github'];
protected $socialite;
protected $userRepo;
/**
* Create a new authentication controller instance.
*
* @return void
* @param Socialite $socialite
* @param UserRepo $userRepo
*/
public function __construct()
public function __construct(Socialite $socialite, UserRepo $userRepo)
{
$this->middleware('guest', ['except' => 'getLogout']);
$this->socialite = $socialite;
$this->userRepo = $userRepo;
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
......@@ -56,15 +66,110 @@ class AuthController extends Controller
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @param array $data
* @return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
/**
* Show the application login form.
*
* @return \Illuminate\Http\Response
*/
public function getLogin()
{
if (view()->exists('auth.authenticate')) {
return view('auth.authenticate');
}
$socialDrivers = $this->getActiveSocialDrivers();
return view('auth.login', ['socialDrivers' => $socialDrivers]);
}
/**
* Redirect to the relevant social site.
* @param $socialDriver
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function getSocialLogin($socialDriver)
{
$driver = $this->validateSocialDriver($socialDriver);
return $this->socialite->driver($driver)->redirect();
}
/**
* The callback for social login services.
*
* @param $socialDriver
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws UserNotFound
*/
public function socialCallback($socialDriver)
{
$driver = $this->validateSocialDriver($socialDriver);
// Get user details from social driver
$socialUser = $this->socialite->driver($driver)->user();
$user = $this->userRepo->getByEmail($socialUser->getEmail());
// Redirect if the email is not a current user.
if ($user === null) {
throw new UserNotFound('A user with the email ' . $socialUser->getEmail() . ' was not found.', '/login');
}
\Auth::login($user, true);
return redirect($this->redirectPath);
}
/**
* Ensure the social driver is correct and supported.
*
* @param $socialDriver
* @return string
* @throws SocialDriverNotConfigured
*/
protected function validateSocialDriver($socialDriver)
{
$driver = trim(strtolower($socialDriver));
if (!in_array($driver, $this->validSocialDrivers)) abort(404, 'Social Driver Not Found');
if(!$this->checkSocialDriverConfigured($driver)) throw new SocialDriverNotConfigured;
return $driver;
}
/**
* Check a social driver has been configured correctly.
* @param $driver
* @return bool
*/
protected function checkSocialDriverConfigured($driver)
{
$upperName = strtoupper($driver);
$config = [env($upperName . '_APP_ID', false), env($upperName . '_APP_SECRET', false), env('APP_URL', false)];
return (!in_array(false, $config) && !in_array(null, $config));
}
/**
* Gets the names of the active social drivers.
* @return array
*/
protected function getActiveSocialDrivers()
{
$activeDrivers = [];
foreach($this->validSocialDrivers as $driverName) {
if($this->checkSocialDriverConfigured($driverName)) {
$activeDrivers[$driverName] = true;
}
}
return $activeDrivers;
}
}
......
......@@ -82,6 +82,10 @@ Route::group(['middleware' => 'auth'], function () {
Route::get('/login', 'Auth\AuthController@getLogin');
Route::post('/login', 'Auth\AuthController@postLogin');
Route::get('/logout', 'Auth\AuthController@getLogout');
// Login using social authentication
Route::get('/login/service/{socialService}', 'Auth\AuthController@getSocialLogin');
Route::get('/login/service/{socialService}/callback', 'Auth\AuthController@socialCallback');
// Password reset link request routes...
Route::get('/password/email', 'Auth\PasswordController@getEmail');
Route::post('/password/email', 'Auth\PasswordController@postEmail');
......
<?php namespace Oxbow\Repos;
use Oxbow\User;
class UserRepo
{
protected $user;
/**
* UserRepo constructor.
* @param $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
public function getByEmail($email) {
return $this->user->where('email', '=', $email)->first();
}
}
\ No newline at end of file
......@@ -8,7 +8,8 @@
"php": ">=5.5.9",
"laravel/framework": "5.1.*",
"intervention/image": "^2.3",
"barryvdh/laravel-ide-helper": "^2.1"
"barryvdh/laravel-ide-helper": "^2.1",
"laravel/socialite": "^2.0"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
......
......@@ -26,7 +26,7 @@ return [
|
*/
'url' => 'http://localhost',
'url' => env('APP_URL', 'http://localhost'),
/*
|--------------------------------------------------------------------------
......@@ -136,6 +136,7 @@ return [
Illuminate\Translation\TranslationServiceProvider::class,
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
Laravel\Socialite\SocialiteServiceProvider::class,
/**
* Third Party
......@@ -199,6 +200,7 @@ return [
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'Socialite' => Laravel\Socialite\Facades\Socialite::class,
/**
* Third Party
......
......@@ -14,7 +14,7 @@ return [
|
*/
'mailgun' => [
'mailgun' => [
'domain' => '',
'secret' => '',
],
......@@ -23,16 +23,28 @@ return [
'secret' => '',
],
'ses' => [
'ses' => [
'key' => '',
'secret' => '',
'region' => 'us-east-1',
],
'stripe' => [
'stripe' => [
'model' => Oxbow\User::class,
'key' => '',
'secret' => '',
],
'github' => [
'client_id' => env('GITHUB_APP_ID', false),
'client_secret' => env('GITHUB_APP_SECRET', false),
'redirect' => env('APP_URL') . '/login/service/github/callback',
],
'google' => [
'client_id' => env('GOOGLE_APP_ID', false),
'client_secret' => env('GOOGLE_APP_SECRET', false),
'redirect' => env('APP_URL') . '/login/service/google/callback',
],
];
......
......@@ -3,6 +3,7 @@ $(function () {
// Notification hiding
$('.notification').click(function () {
$(this).fadeOut(100);
});
// Dropdown toggles
......
......@@ -42,6 +42,9 @@
animation-duration: 3s;
animation-timing-function: ease-in-out;
animation-fill-mode: forwards;
&.stopped {
animation-name: notificationStopped;
}
}
@keyframes notification {
......@@ -58,6 +61,17 @@
transform: translate3d(580px, 0, 0);
}
}
@keyframes notificationStopped {
0% {
transform: translate3d(580px, 0, 0);
}
10% {
transform: translate3d(0, 0, 0);
}
100% {
transform: translate3d(0, 0, 0);
}
}
@keyframes menuIn {
from {
......
......@@ -30,7 +30,6 @@ $button-border-radius: 2px;
border-radius: $button-border-radius;
cursor: pointer;
transition: all ease-in-out 120ms;
text-transform: uppercase;
box-shadow: 0 0.5px 1.5px 0 rgba(0, 0, 0, 0.21);
@include generate-button-colors(#EEE, $primary);
}
......
@extends('public')
@section('sidebar')
@section('content')
<div class="center-box">
<h1>Log In</h1>
......@@ -23,6 +23,16 @@
<button class="button block pos">Sign In</button>
</div>
</form>
@if(count($socialDrivers) > 0)
<hr class="margin-top">
<h3 class="text-muted">Social Login</h3>
@if(isset($socialDrivers['google']))
<a href="/login/service/google" style="color: #DC4E41;"><i class="zmdi zmdi-google-plus-box zmdi-hc-4x"></i></a>
@endif
@if(isset($socialDrivers['github']))
<a href="/login/service/github" style="color:#000;"><i class="zmdi zmdi-github zmdi-hc-4x"></i></a>
@endif
@endif
</div>
@stop
\ No newline at end of file
......
......@@ -2,7 +2,7 @@
@section('body-class', 'image-cover login')
@section('sidebar')
@section('content')
<div class="text-center">
......
......@@ -2,7 +2,7 @@
@section('body-class', 'image-cover login')
@section('sidebar')
@section('content')
<div class="text-center">
......
......@@ -31,7 +31,7 @@
@endif
@if(Session::has('error'))
<div class="notification anim neg">
<div class="notification anim neg stopped">
<i class="zmdi zmdi-alert-circle"></i> <span>{{ Session::get('error') }}</span>
</div>
@endif
......
......@@ -6,14 +6,25 @@
<link rel="stylesheet" href="/css/app.css">
<link href='//fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,300italic,100,300' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="/bower/material-design-iconic-font/dist/css/material-design-iconic-font.min.css">
<!-- Scripts -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="/js/common.js"></script>
</head>
<body class="@yield('body-class')">
<section id="sidebar">
@yield('sidebar')
</section>
@if(Session::has('success'))
<div class="notification anim pos">
<i class="zmdi zmdi-mood"></i> <span>{{ Session::get('success') }}</span>
</div>
@endif
@if(Session::has('error'))
<div class="notification anim neg stopped">
<i class="zmdi zmdi-alert-circle"></i> <span>{{ Session::get('error') }}</span>
</div>
@endif
<section class="container">
@yield('content')
......
......@@ -8,18 +8,18 @@
@include('form/text', ['name' => 'email'])
</div>
@if(isset($model))
@if($currentUser->can('user-update'))
<div class="form-group">
<span class="text-muted">
Only fill the below if you would like <br>to change your password:
</span>
<label for="role">User Role</label>
@include('form.role-select', ['name' => 'role', 'options' => \Oxbow\Role::all(), 'displayKey' => 'display_name'])
</div>
@endif
@if($currentUser->can('user-update'))
@if(isset($model))
<div class="form-group">
<label for="role">User Role</label>
@include('form.role-select', ['name' => 'role', 'options' => \Oxbow\Role::all(), 'displayKey' => 'display_name'])
<span class="text-muted">
Only fill the below if you would like <br>to change your password:
</span>
</div>
@endif
......