Jump to content

user module for login, logout, register


Recommended Posts

Hello,

I found some code examples to build a frontend user login. I thinking about a little module/ extension for it... but after some searching I've the question what could be the best way to do it...

Login and logout already buildin with the following methods

$session->login()
$session->logout()

API pages:

http://processwire.com/api/variables/user/

http://processwire.com/api/variables/session/

How to create a new user or set a password found here

http://processwire.com/api/variables/user/

So I need custum methods to register a new user, update password/ profile and reset a password.

The needed code could be found here at the forum :)

https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/page-2?hl=%2Bregister+%2Bconfirm#entry50183

https://processwire.com/talk/topic/4066-activate-user-account-via-email/

https://processwire.com/talk/topic/107-custom-login/?p=11290

...

But I think it's not needed to create a new class with all methods and so duplicate/ wrap already existing functions...

Should I hook into session or user to add "missing" methods? 

How to addHook found here:

http://processwire.com/api/hooks/#add_new_method

https://processwire.com/talk/topic/1186-how-do-i-extend-user/?p=10507

It's my first try to build a pw / php module... so be forgiving my stupid questions  :-[

  • Like 2
Link to comment
Share on other sites

Have found my way to try it ;)

Created two modules. A "proxy class" which loads an "driver class". The proxy pass-through method calls via __call() to the selected driver. The first driver will work with local PW users. Additional drivers could use another user backend to perform frontend register, login, logout... actions .

So I wrap all actions into a driver to make it changeable.

Link to comment
Share on other sites

  • 2 weeks later...

So, how is it going? 

I've started to write my own module for register/login/logout, but maybe you would like to share your solution?

Though, I'm not convinced about your choice to use two modules instead of one, but on the other hand - maybe I don't understand something yet :).

Link to comment
Share on other sites

Modified my solution. So I need one module and a driver (first: local PW users). So backend could be changed with a new driver (for example to use forum users or ldap auth).

I use forum snippets to build login / register / logout and also a user profile is planned. The PW template is used as controller and I start with default templates inside the module directory. If templates exist at PW template subfolder <MODULE NAME> that will be used.

At the moment there isn't much code to share, but I'll need to build it for a own project. After base features are useable and a little code cleanup I can share it as module...

  • Like 2
Link to comment
Share on other sites

Update

Module FrontendUsers to handle login, logout, register and user profiles.

  • backend related methods moved to the driver FrontendUsersPW (PW local users) so could be replaced with other user backends in the future...
  • default templates/ views within the module directory
  • overwrite default templates with custom code by place in templates/FrontendUsers/ (login.tpl.php, register.tpl.php)
  • use form api and CSRF to build form fields
  • use templateFile class to work with templates and render them

ToDo

First try to build a module... work in progress ;)

  • Like 2
Link to comment
Share on other sites

  • 2 weeks later...

Yeah, I like PW api and module / hook concept :) Learned a lot!

rebuild my (dev) module with key features:

  • register login, logout
  • used hooks to create a profile page after register and send a activation email
  • profiles handled by pages (simple pages with different template)
  • use form api and csrf token  to generate form fields, but forms rendered with template files (templateFile class)

Code examples to build the module found here at various forum topics.

Register, login, logout and profiles working, but its not useable as is at the moment ;)

  • Like 1
Link to comment
Share on other sites

  • 3 months later...

Another possible and very simple way to setup a Frontend-login: Use the ProcessLogin.module from core within a login Template.
 

<?php 

/**
 * Frontend Login template
 *
 */

include("./head.inc"); 
echo = $modules->get('ProcessLogin')->execute();
include("./foot.inc"); 

or to prevent from redirecting with a few lines more code
 

<?php 

/**
 * Frontend Login template
 *
 */

include("./head.inc"); 

//to prevent from redirecting to backend, happens anyway only if loggedIn User has permission page-edit
function noRedirect($event) {
$event->replace = true;
$event->return = $config->urls->root; 
}

$login = $modules->get('ProcessLogin');
$login->addHookAfter('afterLoginRedirect', null, 'noRedirect');
echo $login->execute();

include("./foot.inc"); 

same works with Profile after login

echo $modules->get('ProcessProfile')->execute();

Don't reinvent the wheel like me very often. ;)
To customize the output look here http://processwire.com/api/hooks/

 

  • Like 5
Link to comment
Share on other sites

Hi kixe,

Seems like a cool approach to things, but I just did a little testing and am having some issues - maybe you made some changes to your code just before posting.

Firstly, you need wire('config') because it's inside a function. It can't get the root url the way you have it.

$event->return = wire('config')->urls->root;

Also, the redirect still happens with the code you have. If I change it to a "before" hook it doesn't redirect, but you are stuck with the "Continue" link on the page.

Looking at the edit Profile option - not sure I'd want any front-end only users to have the options to change the admin theme, which will show up in that form if you have more than one installed. It won't be relevant to them and just confusing.

It might seem like more work, but there are simple ways to create your own custom login and profile edit form with not too much code. I have based most of mine off this post by Ryan: https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/?p=15919

  • Like 3
Link to comment
Share on other sites

Hi Adrian,

oops ... thanks for correction. I didn't tested it well. To hide the Continue and get a Logout link instead this should work

if (isset($_GET['logout'])) {
    $session->logout();
    $session->redirect($page->url);
}

if($user->isLoggedin()) {
    echo "<a href='{$page->url}?logout'>Logout</a>";
}
else {
    echo $login->execute();
}



Looking at the edit Profile option - not sure I'd want any front-end only users to have the options to change the admin theme, which will show up in that form if you have more than one installed. It won't be relevant to them and just confusing.

It should be possible to set show/hide user-template-fields in the User-Profil with the Module-Settings or is this not selectable for custom admin-themes?

in the example below I put some more fields to the user template.

modules > Process User Profile > Settings
post-1246-0-99067000-1410190277_thumb.jp

Link to comment
Share on other sites

It should be possible to set show/hide user-template-fields in the User-Profil with the Module-Settings or is this not selectable for custom admin-themes?

I haven't looked to see if it's possible or not, but I wouldn't want to hide it for admin users, just for front-end users using your profile edit approach, so not sure that option would be much help anyway.

Just thinking through scenarios here - not meaning to pull apart your ideas :)

Link to comment
Share on other sites

Good to know! Thanks! :)

Backend plugins (like ldap, external apis,...) could be implemented via a hook...

Maybe I replace my login function with that code.

Because user profiles could be build with user pages (not pw own userprofiles) the final part would be extend the own register function with additional features (email activation, password reset).

At the moment I use a template (without file) with username and password fields and generate a login form via form api / template to form helper module. That works fine, but with reuse the existing module I haven't care about sanitizing input and code security, because it should be updated via PW core ;)

Link to comment
Share on other sites

This makes the messages visible.
 

I'm not sure what login you mean but for custom login using $session->login(user,password) you'd have to code it like this:

//..
try{
    $u = $session->login($username, $pass);
    if($u && $u->id){
        $session->redirect("/somepage/");
    }
} catch(Exception $e) {
    echo $e->getMessage();
}
 

found here: https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/?p=50501

My post was not ready to use. Sorry. Just another approach. If I have something working well and secure I will post it here. Another way is to start from here.
@Adrian: Thanks for the hint.

It might seem like more work, but there are simple ways to create your own custom login and profile edit form with not too much code. I have based most of mine off this post by Ryan: https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/?p=15919

Link to comment
Share on other sites

@Kixe

Yes, $session->login and a little bit sanitizing values ;)

Works fine, but changed it for testing to use ProcessLogin instead, but login failed without error message. So my custom function is more flexible for my use case (works fine, simple to hook in and know the code *g*)

Link to comment
Share on other sites

Little modification which works proper and doesn't need a hook to prevent from redirecting. Only thing which I couldn't get work is to display the Error Exception thrown by Login Throttle - Solutions welcome.

complete template:

<?php
/**
 * Frontend Login template
 *
 */

include("./head.inc");

try {
if($user->isLoggedin()) {
    if(isset($_GET['logout'])) $modules->get('ProcessLogin')->executeLogout(); // redirect user with page-edit permission to admin otherwise to root-page
    else echo "<a href='{$page->url}?logout'>{$user->name} logout</a>";// no redirect because module isn't called again
} else {
    echo $modules->get('ProcessLogin')->execute();
    if($notices->last()) echo '<br/><strong>'.$notices->last().'</strong>'; // error message from ProcessLogin
    //var_dump($session->getAll());
}
}
catch(Exception $e) {
    echo $e->getMessage();
}
include("./foot.inc");

If you use echo $modules->get('ProcessProfile')->execute(); take care about setting the permissions right and give the frontend-user not page-edit role. Hide role-field and admin-template-field and maybe some others in the module settings.
You should also set the validation of all fields shown in frontend very strict.

Go here:
fields > input > strip tags
and
fields > input > pattern
Check security carfully. Like Adrian I have still some doubts about this way is a save one ...
But I think it is good to test in this direction. I am playing around also with process fields (like in admin template) in frontend - just for development. To have easy access to the good stuff of backend in frontend.

Edited by kixe
Link to comment
Share on other sites

I created a simple login / logout module UserLogin based on my new FormHelper...

<?php

class UserLogin extends WireData implements Module {
    /**
     * getModuleInfo is a module required by all modules to tell ProcessWire about them
     * 
     * @return array
     */
    public static function getModuleInfo() {
        return array(
            'title' => 'UserLogin',
            'summary' => 'Login and logout frontend users',
            'version' => '001',
            'requires' => array('FormHelper'),
        );
    }
    
    private $formSubmit = array('attr' => array('value' => 'Login'));
    private $formFields = array(
        'username' => array(
            'module'    => 'InputfieldText',
            'vars'      => array('name' => 'username', 'label' => 'Username', 'required' => true),
            'attr'      => array('id+name' => 'username'),
        ),
        'password' => array (
            'module'    => 'InputfieldText',
            'vars'      => array('name' => 'password', 'label' => 'Password', 'required' => true),
            'attr'      => array('id+name' => 'password', 'type' => 'password'),
        ),
    );

    public function login($redirect = null) {
        $fh = $this->modules->get('FormHelper');
        $fh->createForm(array('formFields' => $this->formFields, 'formSubmit' => $this->formSubmit));
        $process = $fh->formProcess();
        
        if ($process) { // form ok, sanitizing and execute login process...
            $user = $this->sanitizer->name($process->get('username')->value);
            $pass = $process->get('password')->value;
            
            // Try to login and redirect after user sucessfully logged in...
            $login = $this->processLogin($user, $pass, $redirect);
            
            // Not rediected after tried login...? Set login error message!
            $error = "<p style='color:red;'>{$login}</p>";  // should be added to form as InputfieldMarkup
            return $error . $fh->render();
        }
        // Show login form
        return $fh->render();
        
    }
    
    public function logout($redirect = null) {
        $this->processLogout($redirect);
    }
    
    protected function ___processLogin($user, $pass, $redirect) {
        try {
            $login = $this->session->login($user, $pass);

            if($login && $login->id) {
                $this->session->redirect($redirect, false);
                // redirect - process stops here!!!
            }
            else {
                return "Login failed";
            }
        } 
        catch(Exception $e) {
            return $e->getMessage();
        }
    }
    
    protected function ___processLogout($redirect) {
        $this->session->logout();
        $this->session->redirect($redirect, false);
    }
}

Example usage (template code for /user page, URL segments activated)...

<?php

$fu = $modules->get('UserLogin');

if ($user->isGuest()) {
    $output = $fu->login("{$config->urls->root}/user");
}
elseif ($input->urlSegment1 === 'logout') {
    $fu->logout("{$config->urls->root}/user");
}
else {
    $output = "Username: {$user->name}<br /><a href='{$config->urls->root}/user/logout'>Logout</a><br />";
}

echo '<html><head>'; 

// outpunt needed scripts for inputfield modules, ...
foreach ($config->scripts as $file) { echo "<script type='text/javascript' src='$file'></script>\n"; }
foreach ($config->styles as $file) { echo "<link type='text/css' href='$file' rel='stylesheet' />\n"; } 

echo '</head><body>';
echo $output;    
echo '</body></html>';

Extensions and improvements planned...

Link to comment
Share on other sites

  • 2 weeks later...

First public repo of UserLogin module (dev! unstable!) based on my FormHelper module.

https://bitbucket.org/pwFoo/userlogin/src/02d405031f26c1d55b08db93f23eae8ca144ecc2/UserLogin/UserLogin.module?at=master

Demo usage see readme file.

Basic features are login and logout. If ProcessForgotPassword core module is installed the link is added to login form.

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

At the moment I'm thinking about a correct module name...

I split up the module into 

  • login & logout
  • register
  • profile (no code yet)

Possible addons / plugins like RegisterEmailActivation, ForgotPassword (simple integration with ProcessForgotPassword core module), ... are planned.

I renamed the modules to UserFrontendLogin, UserFrontendRegister and UserFrontendProfile and with a own sub directory inside a folder UserFrontend. So it's possible to extend the module collection with plugins and additional functionalities. 

(also changed Repo: https://bitbucket.org/pwFoo/userfrontend)

modules/UserFrontend/
    /UserFrontendLogin/UserFrontendLogin.module
    /UserFrontendRegister/UserFrontendRegister.module
    /UserFrontendProfile/UserFrontendProfile.module

But how should the module collection named? 

UserFrontend?

FrontendUsers?

User?

... ?

Any suggestions?

UPDATE

UserFrontendProfile initial commit. Edit profile based on ProcessProfile core module. Profile information / fields will be based on (hidden system) user template.

Link to comment
Share on other sites

  • 2 weeks later...
  • 1 year later...

Hi how we can change the markup of specific field in forms ? for example I want to create something like this with my login form. http://www.keenthemes.com/preview/metronic/theme/admin_6/page_user_login_5.html

I can change the wrapper for the form but it do it for all the fields in simple word is there anyway to have our own custom markup for the form ?

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...