I followed this guide to implement my own custom user login. Unfortunately it says Bad credentials during login. This exception comes from line 72 of Symfony\Component\Security\Core\Authentication\Provider\UserAuthenticationProvider. This exception gets thrown because it can't retrieve the user.
What I changed for my custom needs is that the users do not have a username. They will login with their email address. But I think that would be no problem to implement.
security.yml:
security:
encoders:
Acme\UserBundle\Entity\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
administrators:
entity: { class: AcmeUserBundle:User }
firewalls:
secured_area:
pattern: ^/
anonymous: ~
form_login: ~
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
UserRepository:
class UserRepository extends EntityRepository implements UserProviderInterface
{
public function loadUserByUsername($username)
{
$q = $this
->createQueryBuilder('u')
->where('u.email = :email')
->setParameter('email', $username)
->getQuery();
try {
// The Query::getSingleResult() method throws an exception
// if there is no record matching the criteria.
$user = $q->getSingleResult();
} catch (NoResultException $e) {
$message = sprintf(
'Unable to find an active admin AcmeUserBundle:User object identified by "%s".',
$username
);
throw new UsernameNotFoundException($message, 0, $e);
}
return $user;
}
public function refreshUser(UserInterface $user)
{
$class = get_class($user);
if (!$this->supportsClass($class)) {
throw new UnsupportedUserException(
sprintf(
'Instances of "%s" are not supported.',
$class
)
);
}
return $this->find($user->getId());
}
public function supportsClass($class)
{
return $this->getEntityName() === $class
|| is_subclass_of($class, $this->getEntityName());
}
}
login.twig.html:
{% if error %}
<div>{{ error.message }}</div>
{% endif %}
<form action="{{ path('login_check') }}" method="post">
<legend>Login</legend>
<label for="email">Email:</label>
<input type="email" id="email" name="_email" value="{{ email }}"
<label for="password">Password:</label>
<input type="password" id="password" name="_password" />
<button type="submit">Login</button>
</form>
What have I done wrong here? In UserRepository it clearly queries the email as username, so why can't it find the user? I have the speculation that it has something to do with the csrf_token? How can I add it to the controller and twig file? Is this the problem at all oder is it anything else I did wrong?
By default Symfony security uses _username and _password parameters to authenticate user via form submit. You can see it in security configuration reference
form_login:
username_parameter: _username
password_parameter: _password
So you need to place _username field name insteadof _email.
Related
I've set up a react web application that's currently listing all "Employees" from a mongodb.
I'm now trying to "add" employees to the database through a react frontend form.
I've managed to pass the data from the form to the application but I'm unsure of the process I need to go through to actually get that data solidified into an object and stored in the api.
Please excuse my code, it's disgusting as this is my first week learning react(honestly with little js knowledge, that's another story) and I've just patched together like 20 tutorials....
Here's my Form class:
class Form extends React.Component {
state = {
fullname: '',
}
change = e => {
this.setState({
[e.target.name]: e.target.value
});
}
onSubmit = e => {
e.preventDefault();
this.props.onSubmit(this.state)
this.setState({
fullname: ''
})
}
render() {
return <div>
<form>
<input name="fullname" placeholder="Full Name" value={this.state.fullname} onChange={e => this.change(e)} />
<button onClick={e => this.onSubmit(e)}>Submit</button>
</form>
</div>
}
}
and my Listing(?) class:
class EmployeeList extends React.Component {
constructor(props) {
super(props);
this.state = {employee: []};
this.EmployeeList = this.EmployeeList.bind(this)
this.componentDidMount = this.componentDidMount.bind(this)
}
componentDidMount() {
this.EmployeeList();
}
EmployeeList() {
fetch('/api/employees').then(function(data){
return data.json();
}).then( json => {
this.setState({
employee: json
});
console.log(json);
});
}
onSubmit = fields => {
console.log('app component got: ', fields)
}
render() {
//return a mapped array of employees
const employees = this.state.employee.map((item, i) => {
return <div className="row">
<span className="col-sm-6">{item.fullname}</span>
<span className="col-sm-2" id={item.action1}></span>
<span className="col-sm-2" id={item.action2}></span>
<span className="col-sm-2" id={item.action3}></span>
</div>
});
return <div>
<Form onSubmit={fields => this.onSubmit(fields)}/>
<div className="container">
<div className="row">
<div className="col-sm-6 bg-warning"><h3>Full Name</h3></div>
<div className="col-sm-2 bg-success"><h3>Action 1</h3></div>
<div className="col-sm-2 bg-success"><h3>Action 2</h3></div>
<div className="col-sm-2 bg-success"><h3>Action 3</h3></div>
</div>
</div>
<div id="layout-content" className="layout-content-wrapper">
<div className="panel-list">{ employees }</div>
</div>
</div>
}
}
I've managed to pass the data to the listing app evident by
onSubmit = fields => {
console.log('app component got: ', fields)
}
But how can I go about making a post request to store this data I send into an object on the db? And then also reload the page so that the new list of all employee's is shown?
Thanks so much for your time!
You can use fetch API to make POST request as well. Second parameter is the config object wherein you can pass the required request configurations.
fetch('url', {
method: 'post',
body: JSON.stringify({
name: fields.fullname
})
})
.then(response) {
response.json();
}
.then( json => {
this.setState({
employee: json
});
});
Additional Request Configs which can be used :
method - GET, POST, PUT, DELETE, HEAD
url - URL of the request
headers - associated Headers object
referrer - referrer of the request
mode - cors, no-cors, same-origin
credentials - should cookies go with the request? omit, same-origin
redirect - follow, error, manual
integrity - subresource integrity value
cache - cache mode (default, reload, no-cache)
I have gone through
http://adonisjs.com/docs/3.1/database-hooks#_hooks_events
http://adonisjs.com/docs/3.1/encryption-and-hashing#_hashing_values
https://adonisjs.svbtle.com/basic-authentication-with-adonisjs#using-hash-provider_3
https://auth0.com/blog/creating-your-first-app-with-adonisj-and-adding-authentication/
and a few more.
This should be fairly simple, but I don't know why I am not being able to figure it out. I want to use the Authentication tool of Adonis while "signing in". For this I need to Hash passwords before saving. I am stuck here.
View
<h1>Sign up</h1>
{{ form.open({url: '/addNew', action: 'UserController.addNewUser'}) }}
{{ csrfField }}
<div class="field">
{{ form.label('username', 'Choose a username') }}
{{ form.text('username') }}
</div>
<div class="field">
{{ form.label('email', 'Enter email address') }}
{{ form.text('email') }}
</div>
<div class="field">
{{ form.label('password', 'Choose a strong password') }}
{{ form.password('password') }}
</div>
<div class="button">
{{ form.submit('Sign Up') }}
</div>
{{ form.close() }}
Controller: UserController
'use strict'
const Database = use('Database')
const User = use('App/Model/User')
const user = new User()
class UserController {
* index (request, response) {
const users = yield Database.select('*').from('users')
response.json(users)
}
* addNewUser (request, response){
user.name = request.input('username')
user.email = request.input('email')
user.password = request.input('password')
user.entry = "Lorem Ipsum";
//Insert into database
const userId = yield Database
.insert({name: user.name, email: user.email, password: user.password, entry: user.entry})
.into('users')
response.json(userId)
}
}
module.exports = UserController
Model: User
'use strict'
const Lucid = use('Lucid')
class User extends Lucid {
static boot () {
super.boot()
this.addHook('beforeCreate', 'User.encryptPassword')
}
}
module.exports = User
Hook: User
'use strict'
const Hash = use('Hash')
const User = exports = module.exports = {}
User.encryptPassword = function * (next) {
this.password = yield Hash.make(request.input('password'))
yield next
}
Thanks!
You should be using the Model itself to create the record. Why are using the Database provider for that?
No where in the documentation it says to new up a model and then make a call using database provider. So it should be
Controller
* addNewUser (request, response) {
const user = new User()
user.name = request.input('username')
user.email = request.input('email')
user.password = request.input('password')
user.entry = "Lorem Ipsum";
yield user.save()
response.json(user.id)
}
Also inside your hook, you do not have access to the request object. I believe you did not bother reading the docs.
Hook
'use strict'
const Hash = use('Hash')
const User = exports = module.exports = {}
User.encryptPassword = function * (next) {
this.password = yield Hash.make(this.password)
yield next
}
Check the docs for hooks here http://adonisjs.com/docs/3.1/database-hooks#_basic_example
Hook for Adonis v4 inside model
class User extends Model {
static boot () {
super.boot()
this.addHook('beforeCreate', async (userInstance) => {
userInstance.password = await Hash.make(userInstance.password)
})
}
}
Check the docs for hooks here https://adonisjs.com/docs/4.1/database-hooks#_defining_hooks
There's a way to do it without using a Hook or Model. Simply by hashing the password in the controller itself. But I want to do it using the Hook. Anyways, here's the code:
Controller: UserController -> addNewUser()
user.name = request.input('username')
user.email = request.input('email')
const pswd = request.input('password')
user.password = yield Hash.make(pswd)
Note: I am not sure exactly which encryption Hash.make does. But the encryption tool of Adonis cannot verify the password. One more thing, the Hashed passwords always start with $2a$10$. Guys please help!
I am completely new to Angular 2 and form concept. I am trying to POST form data to a POST API call. like this
POST API : http://localohot:8080/**********
Component :
user: any = {
id: null,
gender: null,
mstatus: null,
birthdate: null,
bloodgroup: null
}
userName: any = {
id: null,
personId: null,
displayName: '',
prefix: null,
givenName: null
}
userAddressJSON: any = {
id: null,
personId: null,
address1: null,
address2: null,
cityVillage: null
}
var form = new FormData();
form.append('userid', new Blob(['' + uid], { type: 'application/json' }));
form.append('user', new Blob([JSON.stringify(this.user)], { type: 'application/json' }));
form.append('userName', new Blob([JSON.stringify(this.userName)], { type: 'application/json' }));
form.append('userAddress', new Blob([JSON.stringify(this.userAddressJSON)], { type: 'application/json' }));
Here, I don't know how to make API call.
In our old application they used form data POST in jQuery. Now I am trying to do the same in Angular 2. When I do the form POST in old application they are sending like this
------WebKitFormBoundarybAWvwmP2VtRxvKA7
Content - Disposition: form - data; name = "userid"; filename = "blob"
Content - Type: application / json
------WebKitFormBoundarybAWvwmP2VtRxvKA7
Content - Disposition: form - data; name = "user"; filename = "blob"
Content - Type: application / json
------WebKitFormBoundarybAWvwmP2VtRxvKA7
Content - Disposition: form - data; name = "userName"; filename = "blob"
Content - Type: application / json
------WebKitFormBoundarybAWvwmP2VtRxvKA7
Content - Disposition: form - data; name = "userAddress"; filename = "blob"
Content - Type: application / json
Can any one help me how to do that form POST in Angular 2.
Here is how I currently make a POST call in my Angular 2 app, because it sounds like you could use a simple example of how to setup a form. Here is the Angular 2 documentation on How to Send Data to the Server.
For even more high level documentation on making AJAX requests in Angular 2 visit this URL.
in my app/app.module.ts
...
import { HttpModule } from '#angular/http';
...
#NgModule({
imports: [
...
HttpModule
...
],
declarations: [
...
],
providers: [ ... ],
bootstrap: [AppComponent],
})
export class AppModule { }
app/system-setup/system-setup.ts
export class SystemSetup {
system_setup_id: number;
name: string;
counter: number;
}
app/form-component/form.component.html (Notice the [(ngModel)], that is what binds the property of the object to the html input element)
<form class="form" (ngSubmit)="saveEdits()" #editSystemSetupForm="ngForm">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="theName" name="name" [(ngModel)]="selectedItem.name" #itemsName="ngModel" required minlength="3"/>
<div [hidden]="itemsName.valid || itemsName.pristine" class="alert alert-danger">Name is required! Min length of 3.</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="">Counter</label>
<input type="number" step=0.01 class="form-control" name="counter" [(ngModel)]="selectedItem.counter" />
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<button type="submit" class="btn btn-success" style="float: right; margin-left: 15px;" [disabled]="!editISystemSetupForm.form.valid" >Save</button>
<button type="button" class="btn btn-danger" style="float: right;" (click)="cancelEdits()">Cancel</button>
</div>
</div>
</form>
in my app/form-component/form.component.ts
import { Component, OnInit, Input, Output, EventEmitter } from '#angular/core';
import { Headers, RequestOptions, Http, Response } from '#angular/http';
import { SystemSetup } from '../system-setup/system-setup';
#Component({
selector: 'app-setup-form',
templateUrl: 'setup-form.component.html',
styleUrls: ['setup-form.component.css']
})
export class SetupFormComponent implements OnInit {
#Input() selectedItem: SystemSetup; // The object to be edited
#Output() finishedEditing = new EventEmitter<number>(); // When the POST is done send to the parent component the new id
// Inject the Http service into our component
constructor(private _http: Http) { }
// User is finished editing POST the object to the server to be saved
saveEdits(): void {
let body = JSON.stringify( this.selectedItem );
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this._http.post('http://localhost:8080/**********', body, options)
.map(this.extractData)
.do(
data => {
this.finishedEditing.emit(data.system_setup_id); // Send the parent component the id if the selectedItem
})
.toPromise()
.catch(this.handleError);
}
/**
* Gets the data out of the package from the AJAX call.
* #param {Response} res - AJAX response
* #returns SystemSetup - A json of the returned data
*/
extractData(res: Response): SystemSetup {
let body = res.json();
if (body === 'failed') {
body = {};
}
return body || {};
}
/**
* Handles the AJAX error if the call failed or exited with exception. Print out the error message.
* #param {any} error - An error json object with data about the error on it
* #returns Promise - A promise with the error message in it
*/
private handleError(error: any): Promise<void> {
// In a real world app, we might use a remote logging infrastructure
// We'd also dig deeper into the error to get a better message
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg); // log to console instead
return Promise.reject(errMsg);
}
}
This URL is the link to the official Angular 2 documentation site, which is a very good reference for anything an Angular 2 developer could want.
I keep getting this error "Some mandatory parameters are missing" and I can't find how to resolve it.
This is my DataController:
//use some models here for Trialdata, Sessions, Rat;
class DataController extends \BaseController {
//Some functions
public function destroy($id)
{
Trialdata::where('id', $id)->delete();
Sessions::where('id', $id)->update(array('sD_reason', 'Excluded'));
Sessions::where('id', $id)->delete();
Rat::where('id', $id)->update(array('sD_reason', Input::get('sD_reason')));
Rat::where ('id', $id)->delete();
//
}
}
This is my route:
Route::resource('data', 'DataController');
This is the form in my view:
{{Form::open(array('route' => 'data.destroy', $parameters = array($entry[0]->id)))}}
{{Form::label('sD_reason', 'Please specify the reasons of the exclusion');}}<br>
<input name="sD_reason" type="text" id="sD_reason">
<button type="button">No, thanks</button>
<button type="submit" href="#">Exclude</butfon>
{{ Form::close() }}
I've look around for similar problems and I believe it's in my Form::open but I can't find the proper syntax.
Try this:
{{ Form::open( array('route' => array('data.destroy', $entry[0]->id) ) ) }}
From the docs:
http://laravel.com/docs/html#opening-a-form
I can login with FOSFacebookBundle and everything works. But, FOSUserBundle does not seem to work because profiler shows Username: anon and Roles: {}. And, there is no user data about logged in user in database. Maybe, I didn't understand how it works. Please, help.
This is my config.yml
fos_user:
db_driver: orm # other valid values are 'mongodb', 'couchdb' and 'propel'
firewall_name: public
user_class: Trade\TradeBundle\Entity\User
fos_facebook:
file: %kernel.root_dir%/../vendor/facebook/src/base_facebook.php
alias: facebook
app_id: my_app_id
secret: app_secret_key
cookie: true
permissions: [user_about_me]
services:
fos_facebook.auth:
class: Trade\TradeBundle\Security\User\Provider\FacebookProvider
arguments:
facebook: "#fos_facebook.api"
userManager: "#fos_user.user_manager"
validator: "#validator"
container: "#service_container"
This is my security.yml
security:
factories:
- "%kernel.root_dir%/../vendor/bundles/FOS/FacebookBundle/Resources/config/security_factories.xml"
role_hierarchy:
ROLE_ADMIN: ROLE_FACEBOOK
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
my_fos_facebook:
id: fos_facebook.auth
firewalls:
public:
pattern: ^/.*
fos_facebook:
app_url: "app_url"
server_url: "server_url"
login_path: /user/login
check_path: /user/login_check
default_target_path: /
provider: my_fos_facebook
anonymous: true
logout:
handlers: ["fos_facebook.logout_handler"]
The code below does not seem to work because when I log in with facebook setTimeout(goLogIn, 500) function inside if is not called.
function goLogIn(){
window.location.href = "{{ path('user_login_check') }}";
}
function onFbInit() {
if (typeof(FB) != 'undefined' && FB != null ) {
FB.Event.subscribe('auth.statusChange', function(response) {
if (response.session || response.authResponse) {
setTimeout(goLogIn, 500);
} else {
window.location.href = "{{ path('_security_logout') }}";
}
});
}
}
These are my controller actions:
/**
* #Route("/user/login", name = "user_login")
*/
public function loginAction()
{
}
/**
* #Route("/user/login_check", name = "user_login_check")
*/
public function loginCheckAction()
{
}
In order for FOSUserBundle to work together with FOSFacebookBundle, you need to specify a specific login route just for the facebook login at security.yml:
public:
fos_facebook:
check_path: /loginFacebook
Of course you are going to need to point that route correctly at routing.yml:
_security_check:
pattern: /loginFacebook
Then you need to change the check URL on the facebook javascript:
function goLogIn(){
window.location.href = "{{ path('_security_check') }}";
}
The last thing is to create the controller and the action for the new route (this is very important, otherwise it's not going to work) and leave it empty:
public function loginFacebookAction()
{
return array();
}
Of course you are going to need to adapt this to your needs, like where I use the DefaultController, you, apperantly, use the UserController.
Hope it helps.
I would guess you are storing empty data because of your permissions request:
permissions: [user_about_me]
I suggest changing to the tutorial recommended:
permissions: [email, user_birthday, user_location]