What would be the best way to retrieve the Username entered on a login form in dart polymer to be read in the next page to which it is redirected?
The login component is as below -
#CustomTag('alfresco-login-form')
class LoginFormComponent extends FormElement with Polymer, Observable {
LoginFormComponent.created() : super.created();
#observable String username = "";
#observable String password = "";
#observable Map loginData = toObservable({
'username' : '',
'password' : ''
});
#observable String serverResponse = '';
HttpRequest request;
void submitForm(Event e, var detail, Node target) {
e.preventDefault(); // Don't do the default submit.
request = new HttpRequest();
request.onReadyStateChange.listen(onData);
// POST the data to the server.
var url = 'http://127.0.0.1/alfresco/service/api/login';
request.open("POST", url);
request.send(_loginDataAsJsonData());
}
void onData(_) {
if (request.readyState == HttpRequest.DONE &&
request.status == 200) {
// Data saved OK.
serverResponse = 'Server Sez: ' + request.responseText;
Map parsedMap = JSON.decode(request.responseText);
var currentTicket = new Ticket(parsedMap["data"]["ticket"]);
//keeps the back history button active
//window.location.assign('dashboard.html');
//doesn't keep the back history button active
//doesn't put the originating page in the session history
window.location.replace('dashboard.html');
} else if (request.readyState == HttpRequest.DONE &&
request.status == 0) {
// Status is 0...most likely the server isn't running.
serverResponse = 'No server';
}
}
String _loginDataAsJsonData(){
return JSON.encode(loginData);
}
}
I need to have access to that loginData['username'] & parsedMap["data"]["ticket"] to be available in the page dashboard.html.
Not really an answer, but to long for a comment:
Your code shows how you send the credentials to the server. So my previous comment still fits. You can't just pass variables to a new page. When a page is loaded this is like a application restart. You can pass values in the URL you redirect to, as cookies if both pages are loaded from the same domain or you can just reload them from the server where you stored them previously. To know that the new page is was requested by the same user you have to use some session handling (like the previously mentioned session cookie). This has nothing to do with Dart or Polymer this is more about how the web works.
Related
I want to check the user log in parameters, and if the parameters accepted, I want the server to send back to the client both the name and roles of the user, to be saved in the SeassonStorage for further usages.
my server side code is:
....
....
var users = <Map>[];
var logged = <Map>[];
....
....
.then((_) {
for (var user in users)
if(_theData['userName']==user['Alias'] && _theData['password']==user['Password'])
{
userFound=true;;
logged.add({
"Alias":user['Alias'],
"Roles": user['Roles']
});
}
})
.then((_) {
if(userFound == true)
res.write(JSON.encode(logged));
else
res.write('sorry, unknown loggin');
res.close();
});
in the client side, I've:
....
....
if(request.responseText != 'sorry, unknown loggen'){
server_msg.innerHtml='Welcome';
print(request.responseText);
print(JSON.decode(request.responseText));
var FonixLogin = JSON.decode(request.responseText);
print(FonixLogin['Alias']);
print(FonixLogin['Roles']);
Storage sessionStorage = window.sessionStorage;
sessionStorage['FonixAlias'] = FonixLogin['Alias'];
sessionStorage['FonixRoles'] = FonixLogin['Roles'];
....
the output I get is:
[{"Alias":"Admin","Roles":"admin"}]
[{Alias: Admin, Roles: admin}]
Exception: Illegal argument(s): Alias login.dart:66login_Element.onData
Why mistake I made here, so that the returned data is not saved properly in the
FonixLogin is a List and you access it like a Map.
Try print(FonixLogin[0]['Alias']);
I added Shiro session management (based on Kim's and Leif's webinar) to the Vaadin quick ticket dashboard demo application. When I do a browser reload in the application I get thrown back to the login page with no session. How / where can I prevent this.
I have a standard shiro.ini setup
Login button handler:
signin.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
boolean loginOK = false;
Factory<SecurityManager> factory =
new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager((org.apache.shiro.mgt.SecurityManager)
securityManager);
Subject currentUser = SecurityUtils.getSubject();
//collect user principals and credentials in a gui specific manner
//such as username/password html form, X509 certificate, OpenID, etc.
//We'll use the username/password example here since it is the most common.
UsernamePasswordToken token =
new UsernamePasswordToken(username.getValue(), password.getValue());
//this is all you have to do to support 'remember me' (no config - built in!):
token.setRememberMe(true);
//currentUser.login(token);
try {
logger.log(Level.INFO, "trying login");
currentUser.login( token );
logger.log(Level.INFO, "login done");
//if no exception, that's it, we're done!
} catch ( Exception e ) {
logger.log(Level.INFO, "exception");
}
if ( currentUser.hasRole( "schwartz" ) ) {
loginOK = true;
} else {
loginOK = false;
}
if (loginOK) {
signin.removeShortcutListener(enter);
buildMainView();
} else {
if (loginPanel.getComponentCount() > 2) {
// Remove the previous error message
loginPanel.removeComponent(loginPanel.getComponent(2));
}
// Add new error message
Label error = new Label(
"Wrong username or password. <span>Hint: try empty values</span>",
ContentMode.HTML);
error.addStyleName("error");
error.setSizeUndefined();
error.addStyleName("light");
// Add animation
error.addStyleName("v-animate-reveal");
loginPanel.addComponent(error);
username.focus();
}
}
});
Use #preserveonRefresh annotation in UI init class
I recommend using Shiro's web filter. This way, your session will not be lost and you can prohibit unauthorized actions (e.g. Instantiating view objects) easily since Shiro's context is already set up when you display the login or any other view.
I'm using angularjs for the front end and rails + devise for authentication on the backend.
On the front end I have added a responseInterceptor to redirect to the /#/sign_in page upon any 401 response from any xhr request and display a growl style pop-up message using toastr.
App.config(['$httpProvider', function ($httpProvider) {
$httpProvider.responseInterceptors.push('securityInterceptor');
}]);
App.factory('securityInterceptor', ['$injector', '$location', '$cookieStore', function ($injector,$location,$cookieStore) {
return function(promise) {
var $http = $injector.get('$http');
return promise.then(null, function(response){
if (response.status === 401) {
$cookieStore.remove('_angular_devise_user');
toastr.warning('You are logged out');
$location.path('/#/sign_in');
}
});
};
});
My problem is, when I click on a page that loads several xhr requests during the controllers initialization, for example:
var products = Product.query();
var categories = Category.query();
var variations = Variation.query();
These are needed for various navigation components and they all fire off in parallel, resulting in several duplicate growl-style messages.
Is there a way to make angular quit on the first 401 and stop execution of the rest of the controller from within the interceptor? In a traditional rails app, there would be a "before_filter" that stops regular execution, preventing the page and queries from loading... what's the best way to do this in angular?
I've been pondering about this problem for my own apps too. A sketch of my thoughts (NOT REAL IMPLEMENTATION, SO BEWARE):
A userData service keeps track of whether the user is logged in + other information (e.g. user name, real user name etc):
App.service("userData", function() {
var currentData = {
loggedIn: false
};
function getCurrent() {
return currentData;
}
// called when the user logs in with the user data
function loggedIn(userData) {
// the object is REPLACED to avoid race conditions, see explanation below
currentData = angular.extend({loggedIn: true}, userData);
}
return {
getCurrent: getCurrent,
loggedIn: loggedIn
};
});
The interceptors keep track of the currentData. If an interceptor receives HTTP 401 and the loggedIn flag is true, it changes the flag to false and redirects to the login view. If an interceptor receives HTTP 401 and the loggedIn flag is false, it does nothing besides rejecting the request, because another interceptor has done the view redirection.
When the user logs in, the currentData is replaced, so as to avoid situations with delayed responses (e.g. call1 and call2 are initiated, call1 responds 401; call2 also results in 401, but the delivery of the actual response is delayed; then the user logs in again; then call2 receives its 401; the second 401 should not overwrite the current state)
App.config(["$provide", "$httpProvider", function($provide, $httpProvider) {
$provide.factory("myHttpInterceptor", ["$q", "userData", "$cookieStore", "toastr", "$location",
function($q, userData, $cookieStore, toastr, $location) {
return {
request: function(config) {
config.currentUserData = userData.getCurrent();
return config;
},
responseError: function(rejection) {
if( rejection && rejection.status === 401 && rejection.config && rejection.config.currentUserData && rejection.config.currentUserData.loggedIn ) {
rejection.config.currentUserData.loggedIn = false;
$cookieStore.remove('_angular_devise_user');
toastr.warning('You are logged out');
$location.path('/#/sign_in');
}
return $q.reject(rejection);
}
};
}
]);
$httpProvider.interceptors.push("myHttpInterceptor");
});
Also note I am using the newer way to register interceptors, as $httpProvider.responseInterceptors seems to be deprecated.
I am using Asp.Net with MVC 4 to build a web application. For authentication, I am using forms authentication. The login page is set correctly and login behaves properly. However, instead of using the default partial login view I am using my own and I use AJAX to log in.
The login controller works fine and here is the code for login.
Here is my code in login action. Here resp is my custom response object
resp.Status = true;
// sometimes used to persist user roles
string userData = "some user data";
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // ticket version
login.username, // authenticated username
DateTime.Now, // issueDate
DateTime.Now.AddMinutes(30), // expiryDate
false, // true to persist across browser sessions
userData, // can be used to store additional user data
FormsAuthentication.FormsCookiePath); // the path for the cookie
// Encrypt the ticket using the machine key
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
// Add the cookie to the request to save it
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
cookie.HttpOnly = true;
//Response.Cookies.Add(cookie);
Response.SetCookie(cookie);
return Json(resp);
Here is the code of cshtml page to handle this script response
function (respData) {
if (respData.Status) {
window.location.href = "/";
}
if (!respData.Status) {
if (respData.Errors[0].ErrorCode == 1) {
$('#invalid').show();
$('#username').val('');
$('#password').val('');
}
else if (respData.Errors[0].ErrorCode == -1) {
var msg = respData.Errors[0].ErrorDescription;
$('#error_email').text(msg);
}
else {
var msg = respData.Errors[0].ErrorDescription;
$('#error_pwd').text(msg);
}
}
$("#dialog").dialog("close");
},
Everything works fine and the user is successfully redirected to home page on successful login. Also gets a proper message on failure.
The problem is, when I browse any other page after this successful redirection, the subsequent requests are not authenticated.
I did a little bit research and found that the browser is not sending the forms authentication cookie in the subsequent requests and hence those requests are not authenticated.
Any idea on this behavior ? , Am I missing something ?
Try explicitly setting the expiry time on your cookie with:
Cookie.Expires(DateTime.Now.AddMinutes(30));
Suppose I logged into my device's Facebook authentication, like system Facebook on iOS. I obtain an access token.
How can I use the access token to login to Meteor's Facebook Oauth provider?
To login with Facebook using an access token obtained by another means, like iOS Facebook SDK, define a method on the server that calls the appropriate Accounts method:
$FB = function () {
if (Meteor.isClient) {
throw new Meteor.Error(500, "Cannot run on client.");
}
var args = Array.prototype.slice.call(arguments);
if (args.length === 0) {
return;
}
var path = args[0];
var i = 1;
// Concatenate strings together in args
while (_.isString(args[i])) {
path = path + "/" + args[i];
i++;
}
if (_.isUndefined(path)) {
throw new Meteor.Error(500, 'No Facebook API path provided.');
}
var FB = Meteor.npmRequire('fb');
var fbResponse = Meteor.sync(function (done) {
FB.napi.apply(FB, [path].concat(args.splice(i)).concat([done]));
});
if (fbResponse.error !== null) {
console.error(fbResponse.error.stack);
throw new Meteor.Error(500, "Facebook API error.", {error: fbResponse.error, request: args});
}
return fbResponse.result;
};
Meteor.methods({
/**
* Login to Meteor with a Facebook access token
* #param accessToken Your Facebook access token
* #returns {*}
*/
facebookLoginWithAccessToken: function (accessToken) {
check(accessToken, String);
var serviceData = {
accessToken: accessToken
};
// Confirm that your accessToken is you
try {
var tokenInfo = $FB('debug_token', {
input_token: accessToken,
access_token: Meteor.settings.facebook.appId + '|' + Meteor.settings.facebook.secret
});
} catch (e) {
throw new Meteor.Error(500, 'Facebook login failed. An API error occurred.');
}
if (!tokenInfo.data.is_valid) {
throw new Meteor.Error(503, 'This access token is not valid.');
}
if (tokenInfo.data.app_id !== Meteor.settings.facebook.appId) {
throw new Meteor.Error(503, 'This token is not for this app.');
}
// Force the user id to be the access token's user id
serviceData.id = tokenInfo.data.user_id;
// Returns a token you can use to login
var loginResult = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, {});
// Login the user
this.setUserId(loginResult.userId);
// Return the token and the user id
return loginResult;
}
}
This code depends on the meteorhacks:npm package. You should call meteor add meteorhacks:npm and have a package.json file with the Facebook node API: { "fb": "0.7.0" }.
If you use demeteorizer to deploy your app, you will have to edit the output package.json and set the scrumptious dependency from "0.0.1" to "0.0.0".
On the client, call the method with the appropriate parameters, and you're logged in!
In Meteor 0.8+, the result of Accounts.updateOrCreateUserFromExternalService has changed to an object containing {userId: ...} and furthermore, no longer has the stamped token.
You can get the accessToken in the Meteor.user() data at Meteor.user().services.facebook.accessToken (be aware this can only be accessed on the server side as the services field is not exposed to the client.
So when a user logs in with facebook on your meteor site these fields would be populated with the user's facebook data. If you check your meteor user's database with mongo or some other gui tool you could see all the fields which you have access to.
Building on DrPangloss' most excellent answer above, combining it with this awesome post: http://meteorhacks.com/extending-meteor-accounts.html
You'll run into some issues using ObjectiveDDP in trying to get the client persist the login. Include the header:
#import "MeteorClient+Private.h"
And manually set the required internals. Soon I'll make a meteorite package and an extension to MyMeteor (https://github.com/premosystems/MyMeteor) but for now it's manual.
loginRequest: {"accessToken":"XXXXXb3Qh6sBADEKeEkzWL2ItDon4bMl5B8WLHZCb3qfL11NR4HKo4TXZAgfXcySav5Y8mavDqZAhZCZCnDDzVbdNmaBAlVZAGENayvuyStkTYHQ554fLadKNz32Dym4wbILisPNLZBjDyZAlfSSgksZCsQFxGPlovaiOjrAFXwBYGFFZAMypT9D4qcZC6kdGH2Xb9V1yHm4h6ugXXXXXX","fbData":{"link":"https://www.facebook.com/app_scoped_user_id/10152179306019999/","id":"10152179306019999","first_name":"users' first name","name":"user's Full Name","gender":"male","last_name":"user's last name","email":"users#email.com","locale":"en_US","timezone":-5,"updated_time":"2014-01-11T23:41:29+0000","verified":true}}
Meteor.startup(
function(){
Accounts.registerLoginHandler(function(loginRequest) {
//there are multiple login handlers in meteor.
//a login request go through all these handlers to find it's login hander
//so in our login handler, we only consider login requests which has admin field
console.log('loginRequest: ' + JSON.stringify(loginRequest));
if(loginRequest.fbData == undefined) {
return undefined;
}
//our authentication logic :)
if(loginRequest.accessToken == undefined) {
return null;
} else {
// TODO: Verfiy that the token from facebook is valid...
// https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.0#checktoken
// graph.facebook.com/debug_token? input_token={token-to-inspect}&access_token={app-token-or-admin-token}
}
//we create a user if not exists, and get the userId
var email = loginRequest.fbData.email || "-" + id + "#facebook.com";
var serviceData = {
id: loginRequest.fbData.id,
accessToken: loginRequest.accessToken,
email: email
};
var options = {
profile: {
name: loginRequest.fbData.name
}
};
var user = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, options);
console.log('Logged in from facebook: ' + user.userId);
//send loggedin user's user id
return {
userId: user.userId
}
});
}
);
This answer could be improved further as we can now directly debug the token from a REST http request using futures. Credit still goes to #DoctorPangloss for the principal steps necessary.
//Roughly like this - I removed it from a try/catch
var future = new Future();
var serviceData = {
accessToken: accessToken,
email: email
};
var input = Meteor.settings.private.facebook.id + '|' + Meteor.settings.private.facebook.secret
var url = "https://graph.facebook.com/debug_token?input_token=" + accessToken + "&access_token=" + input
HTTP.call( 'GET', url, function( error, response ) {
if (error) {
future.throw(new Meteor.Error(503, 'A error validating your login has occured.'));
}
var info = response.data.data
if (!info.is_valid) {
future.throw(new Meteor.Error(503, 'This access token is not valid.'));
}
if (info.app_id !== Meteor.settings.private.facebook.id) {
future.throw(new Meteor.Error(503, 'This token is not for this app.'));
}
// Force the user id to be the access token's user id
serviceData.id = info.user_id;
// Returns a token you can use to login
var user = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, {});
if(!user.userId){
future.throw(new Meteor.Error(500, "Failed to create user"));
}
//Add email & user details if necessary
Meteor.users.update(user.userId, { $set : { fname : fname, lname : lname }})
Accounts.addEmail(user.userId, email)
//Generate your own access token!
var token = Accounts._generateStampedLoginToken()
Accounts._insertLoginToken(user.userId, token);
// Return the token and the user id
future.return({
'x-user-id' : user.userId,
'x-auth-token' : token.token
})
});
return future.wait();
Use this instead of the JS lib suggested by #DoctorPangloss. Follow the same principles he suggested but this avoids the need to integrate an additional library