Laravel 5 User activation - laravel-5.1

I have a strange problem that I can't solve.
When a user is registered, I redirect them to a feed url, open a modal and tell my user to activate his account by clicking the email link that I sent them. But after I click the link, I keep being redirected to the exact same page (feed) and my account isn't being activated. What could be the problem here?
routes.php
Route::group(['namespace' => 'Auth'], function ()
{
Route::group(['middleware' => 'auth'], function ()
{
Route::get('activate/{token}', 'PasswordController#activate');
});
});
PasswordController
public function activate($token) {
//get token value.
// find the user that belongs to that token.
$activation = User::where("confirmation_code", $token)->get()->first();
$activation->confirmed = 1;
$activation->save();
}
RedirectIfAuthenticated.php If I remove feed url, it works. But I don't want to do that.
public function handle($request, Closure $next)
{
if ($this->auth->check()) {
return redirect('/feed');
}
return $next($request);
}

Assuming your using laravel default authentication system. Do the following.
In your AuthController add the method. This will create the user but not log them in since they haven't activated their account. Please note laravel will automatically login the user hence the function below overrides default behaviour.
public function postRegister(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
$this->create($request->all());
return redirect('/feed');
}
In RedirectIfAuthenticated.php remove '/feed' and instead have a url which users are to be redirected if logged in. Since having feed there will redirect user to the page asking them to activate there account every time they log in.
In the activate function of your password controller there is no logic as to what should be done once user is activated. Add the following lines after $activation->save()
Auth::login($activation);
return redirect('/');

Related

How to create a login function without using spring security with grails 3 using interceptors

System has two grails apps:
the private backoffice which uses springsecurity and an Operator domain object holding the operators username, password, number of failed logins etc.
the public web front end where users signup, login, and use the system. The User domain object holds the users username, password etc.
Because we are using springsecuirty for the backoffice, I assume we cant use it again for the web (the config and db will conflict). Also, the web just needs a very basic auth (all pages require a valid session except register and the login form itself).
Setting up the login form and the interceptor are easy.
The question is, what should the login form actually do in the controller? I can check the username and password match whats in the DB, then I presumably need to create a session, with session timeouts etc. Where do I look for documentation on how to do this? http://docs.grails.org/3.1.1/ref/Servlet%20API/session.html Tells you how to logout, but not login. I presumably need to store sessions in the DB (so that the user can hit any server) etc.
By looking at some of my old java code, I have got some of the way there.
The interceptor looks like this:
class AuthInterceptor {
public AuthInterceptor() {
// allow the login form and register form to work.
matchAll().excludes(controller: 'auth')
}
boolean before() {
if(session.getAttribute("user")== null ) {
// jump to the login form if there is no user attribute.
redirect controller: 'auth', action: 'login'
return false
}
true
}
boolean after() { true }
void afterView() {
// no-op
}
The controller looks like this:
class AuthController {
def index() { }
def login() {
def email = params.email
def password = params.password
if (email != null) {
// It would be better to invalidate the old session
// but if we do, we cant get a new one...
// session.invalidate()
User user = User.findByEmail(email);
if (user != null) {
log.error("user.pass:" + user.password + " pass:" + password)
// #TODO handle password encryption
if (user.password == password) {
session.setAttribute("user", user)
redirect(controller:"dashboard")
}
}
flash.message = "email or password incorrect"
}
render (view:"login")
} // login()
However, I have not found where we can set the session timeout yet.

How to redirect login plus previous URL in laravel

Laravel 5.1
I'm trying to build this functionality for every method in my controller. And this is very unpractical to do and very difficult to maintain. How can I set this that is when I registered an auth middleware in a specific route then it will redirect into a login page together with the URL that trying to view/visit.
Example:
URL: public/users
If this URL will try to visit by an unauthenticated user, then the user will be redirected to a url like public/login?url=http://localhost/myproject/public/users
Then After the user loggedin successfully, the user then will be redirected into http://localhost/myproject/public/users
What I have now: (But I think not a good one to use)
public function getLoginURL(){
if(!Input::get('location-login')){
// URL is not set, redirect user to home.
return redirect('/');
}
if(auth()->check()){
// User is logged in. Go the specified URL (depends on the middleware of the url (route))
return redirect()->to(Input::get('location-login'));
}
if(!auth()->check()){
// Redirect user to a login with the URL provided
return view('pages::auth.login.url');
}
}
You can use the next method in middleware... no need to send the url
public function handle($request, Closure $next)
{
if (Auth::user()) {
return $next($request);
}
return redirect('/login');
}
Use this in your AuthController
namespace App\Http\Controllers;
use Auth;
use Illuminate\Routing\Controller;
class AuthController extends Controller
{
/**
* Handle an authentication attempt.
*
* #return Response
*/
public function authenticate()
{
if (Auth::attempt(['email' => $email, 'password' => $password])) {
// Authentication passed...
return redirect()->intended('dashboard');
}
}
}
intended() function will redirect you to your intended location.
Check the full detail here Intended redirect

Updating Twitter status using LinqToTwitter

here's what set out to do:
Make an MVC app on which the user clicks a button and is taken to the Twitter login page
After giving the credentials the user is redirected to a second page
On the secong page there is a text box and a 'Tweet' button
Entering a message and clicking on 'Tweet' will update the status
I got till the 2nd point by following the samples from LinqToTwitter codeplex page.
The code from OAuth controller works fine and it does redirect back to MVC app's second page.
But I am missing something which is not posting the status.
This is the code in the button click from which I pass the user entered status:
public ActionResult Status(string status)
{
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore()
};
auth.CompleteAuthorizeAsync(Request.Url);
var twitterContext = new TwitterContext(auth);
TweetAsync(twitterContext, status);
return View(); //return some view to the user
}
void TweetAsync(TwitterContext twitterCtx, string statusToUpdate)
{
var tweet = twitterCtx.TweetAsync(statusToUpdate);
if (tweet != null)
{
// Inform the user about success
}
}
Both the above methods are also in OAuth controller.
Can someone please help me with this?
Thanks in advance.
Change your method to use async and return a Task:
public async Task Status(string status)
{
//...
var tweet = await twitterContext.TweetAsync(twitterContext, status);
// ...
}
and then await TweetAsync, assigning the response to a Status entity named tweet. If you want a separate method for calling TweetAsync, make that async also. With async, you must make every method in the call chain async.

Back button doesn't cause postback to a controller action in MVC

When I click the back button in IE10 or Chrome on Win7, it does not hit my break point in my MVC controller. The Network tab in IE developer's tools shows it had a 304 not modified and Fiddler doesn't capture the request.
I was expecting the post back, so I could do work in my controller.
In my case, the bug is:
Sign in
make sure you are on the default page
click the browser back button on the top left you'll now be back to
the login screen
sign in with your same credentials again when you
do that - I get "The provided anti-forgery token was meant for user "", but the current user is "username".
I've tried putting this in my controller, without success:
this.HttpContext.Response.CacheControl = "private";
this.HttpContext.Response.Cache.SetMaxAge(TimeSpan.FromSeconds(0));
public ActionResult Index()
{
// Get: /Home/Index
if (this.User.Identity.IsAuthenticated)
{
// send the user to the GlobalAssetDashboard
return this.RedirectToAction(
"GlobalAssetDashboard",
"Dashboard",
new
{
area = "DashboardArea"
});
}
return this.View("Login");
}
public ActionResult Login()
{
// GET: /Home/Login
if (this.User.Identity.IsAuthenticated)
{
// send the user to the GlobalAssetList
return this.RedirectToAction(
"GlobalAssetDashboard",
"Dashboard",
new
{
area = "DashboardArea"
});
}
return this.View("Login", new LoginModel());
}
Is there a way to force the postback or detect this and cause a refresh in JavaScript? Or maybe I have my controller methods implemented incorrectly?
Typically caching rules like this aren't conditional upon the logic they perform, the URL as a whole is either cached or it isn't. In which case something as simple as this should suffice.
[OutputCache(NoStore=true, Duration=0)]
public ActionResult Login()
{
}
http://msdn.microsoft.com/en-us/library/dd492556(v=vs.108).aspx

ASP.NET MVC Session Expiration

We have an internal ASP.NET MVC application that requires a logon. Log on works great and does what's expected. We have a session expiration of 15 minutes. After sitting on a single page for that period of time, the user has lost the session. If they attempt to refresh the current page or browse to another, they will get a log on page. We keep their request stored so once they've logged in they can continue on to the page that they've requested. This works great.
However, my issue is that on some pages there are AJAX calls. For example, they may fill out part of a form, wander off and let their session expire. When they come back, the screen is still displayed. If they simply fill in a box (which will make an AJAX call) the AJAX call will return the Logon page (inside of whatever div the AJAX should have simply returned the actual results). This looks horrible.
I think that the solution is to make the page itself expire (so that when a session is terminated, they automatically are returned to the logon screen without any action by them). However, I'm wondering if there are opinions/ideas on how best to implement this specifically in regards to best practices in ASP.NET MVC.
Update:
So I went ahead and implemented this in my OnActionExecuting (per Keltex's suggestion)
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.Write("Invalid session -- please login!");
filterContext.HttpContext.Response.End();
}
else
{
...
}
}
This definitely makes things better -- now even if they have two tabs (one with some AJAX calls that they can trigger) and they log out explicitly in the second tab, they will immediately get something that makes more sense rather than a bunch of screwed up AJAX data.
I still think I will implement the Javascript countdown as well that womp suggested.
Specifically, I don't know that there are any best practices regarding it, but I'm doing this right now for our app. We've opted for a client-side solution where we output the Session timeout value into some javascript in the master page, and calculate when the session will expire.
5 minutes before-hand, we pop up a modal dialog box saying "Are you still there?" with a countdown timer. Once the timer hits 0:00, we redirect the browser to the login page.
It's implemented with a minimal amount of javascript to do the time and timer calculations, and a simple .ashx handler that will refresh the session if the user clicks "I'm back!" on the dialog box before the session expires. That way if they return in time, they can refresh the session without any navigation.
I asked similar question yesterday. Here is my solution:
Modified Authorize attribute:
public class OptionalAuthorizeAttribute : AuthorizeAttribute
{
private class Http403Result : ActionResult
{
public override void ExecuteResult(ControllerContext context)
{
// Set the response code to 403.
context.HttpContext.Response.StatusCode = 403;
context.HttpContext.Response.Write(CTRes.AuthorizationLostPleaseLogOutAndLogInAgainToContinue);
}
}
private readonly bool _authorize;
public OptionalAuthorizeAttribute()
{
_authorize = true;
}
//OptionalAuthorize is turned on on base controller class, so it has to be turned off on some controller.
//That is why parameter is introduced.
public OptionalAuthorizeAttribute(bool authorize)
{
_authorize = authorize;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//When authorize parameter is set to false, not authorization should be performed.
if (!_authorize)
return true;
var result = base.AuthorizeCore(httpContext);
return result;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
{
//Ajax request doesn't return to login page, it just returns 403 error.
filterContext.Result = new Http403Result();
}
else
base.HandleUnauthorizedRequest(filterContext);
}
}
HandleUnauthorizedRequest is overridden, so it returns Http403Result when using Ajax. Http403Result changes StatusCode to 403 and returns message to the user in response. There is some additional logic in attribute (authorize parameter), because I turn on [Authorize] in base controller and disable it in some pages.
Other important part is global handling of this response on client side. This is what I placed in Site.Master:
<script type="text/javascript">
$(document).ready(
function() {
$("body").ajaxError(
function(e,request) {
if (request.status == 403) {
alert(request.responseText);
window.location = '/Logout';
}
}
);
}
);
</script>
I place GLOBAL ajax error handler and when evert $.post fails with 403 error, response message is alerted and user is redirected to logout page. Now I don't have to handle error in every $.post request, because it is handled globally.
Why 403, not 401? 401 is handled internally by MVC framework (that is why redirection to login page is done after failed authorization).
What do you think about it?
EDIT:
About resigning from [Authorize] attribute: [Authorize] is not only about checking Identity.IsAuthenticated. It also handles page caching (so you don't cache material that requires authentication) and redirection. There is no need to copy this code.
You might look into the AjaxOptions that can be set in Ajax.BeginForm(). There is an OnBegin setting that you can associate with a javascript function, which could call a Controller method to confirm that the session is still valid, and if not, redirect to the login page using window.location.
Part of the problem appears to be that you're letting the framework do everything. I wouldn't decorate your AJAX method with the [Authorize] attribute. Instead check User.Identity.IsAuthenticated and if it returns false, create sensible error message.
My solution uses one meta-tag on login form and a bit of Javascript/jQuery.
LogOn.cshtml
<html>
<head>
<meta data-name="__loginform__" content="true" />
...
</head>
...
</html>
Common.js
var Common = {
IsLoginForm: function (data) {
var res = false;
if (data.indexOf("__loginform__") > 0) {
// Do a meta-test for login form
var temp =
$("<div>")
.html(data)
.find("meta[data-name='__loginform__']")
.attr("content");
res = !!temp;
}
return res;
}
};
AJAX code
$.get(myUrl, myData, function (serverData) {
if (Common.IsLoginForm(serverData)) {
location.reload();
return;
}
// Proceed with filling your placeholder or whatever you do with serverData response
// ...
});
Here's how I did it...
In my base controller
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 403;
filterContext.HttpContext.Response.Write(SessionTimeout);
filterContext.HttpContext.Response.End();
}
}
}
Then in my global .js file
$.ajaxSetup({
error: function (x, status, error) {
if (x.status == 403) {
alert("Sorry, your session has expired. Please login again to continue");
window.location.href = "/Account/Login";
}
else {
alert("An error occurred: " + status + "nError: " + error);
}
}
});
The SessionTimeout variable is a noty string. I omitted the implementation for brevity.

Resources