Sorry if this is a rookie question but here it goes:
I want the Admin (when logging into the site) to view a link that non-admins can't view when they log in. I'm not even sure how to get started. I know I have to add two separate routes to the routes.js file. But not really sure how to display that in the UI or if I'm even correct.
This repo seems somewhat relatable to my problem. https://github.com/angular-ui/ui-router#get-started
Thanks
So the best way (using angular as you are) to create admin pages is to restrict them on your API within express or node.
Luckily there is a package for this! Passport a node module which can not only do regular logins but also google, facebook and many others.
I would take a look at there middleware examples then in your route you can do something as simple as this:
app.get('/admin', isAdmin ,function(req,res){
res.send('Secret Admin Things')
});
where isadmin will handle checking if they are an admin all in one swoop! Amazing tutorial for this.
I worked on a project which did not make use of passport and this is what they did
In the back end
res.locals = {
auth: req.session.auth,
}
res.render('index');
Then in the front end
HTML:
<span id="admin"> </span>
JavaScript:
if('{{auth}}' == admin){
menu = "<a href='/admin/users'> Admin: Users </a>"
$('#admin').append(menu)
}
Then to make sure someone could not look at the code to find the link and go to it you of course secure the back end
if (req.session.auth !== 'admin') { //
res.redirect('/');
}
The other answers are great if your using and know angular and passport. However, not everyone uses the same libraries so if your just using express and JQuery this option will work to get you started. There is much more to the code as far as security checks etc you would want to do but this is the basic way
Related
I'm hoping to be able to create a section of a site that is unable to be read/seen by anyone that's not logged in... I am using Firebase and Javascript
I have read that you are unable to set permissions for files (.htmls ect) so i wont be able to block people from seeing the pages as a whole... Ive also read that this isn't the best practice anyway... So my question is...
What is the protocol for doing this sort of thing? And how can this be done in Firebase?
I have managed to create a user only page before from a tutorial, but this was just done by hiding the content of the page with Javascript and also blocking the permissions to the displayed data through Firestore permissions.
But I don't feel this is adequate for my site as I don't want people being able to read the code in the background or get access to the page at all to begin with.
I have also read that a way to go about doing this is to use Firebase Cloud Functions to check weather the user is logged in and if they are then it spits out the code for the pages from the google servers. Is this a good idea? Or is there a better way?
Any help, tips or insights would be greatly appreciated.
Just trying to get a feel for where to begin with this problem.
Hoping there is a solution.
Thanks
Yes, its a good practice hiding or preventing the UI to be rendered for unauthorize users.
Yes, its also a good practice setting the permissions accessing your data from the database.
You should also consider middleware, navigation guards or route guards for preventing unauthorized users to visit the restricted page. It would depend on the stack, or what frontend technology you are using. You can find whatever navigation guard you chosse. For vuejs there is vue-router. Also you can use firebase authState listener. Depends on your choice.
Use firebase auth to signInWithEmailAndPassword, or whatever your authentication method was. Then, you can check the auth state in onAuthStateChange, and set your new userId state:
// somewhere...
const [currentUserId, setCurrentUserId] = useState(null)
// later..
onAuthStateChanged(auth, (user) => {
if (user && user.uid) {
setUserId(user.uid)
}
});
// even later in this component:
return (<Layout userId={currentUserId} />);
// in wherever you have links, I assumed you passed currentUserId to here:
return (
currentUserId != null ? (Give content pls) : routeToLogin();
);
Something like this should be fine and secure enough. Noone is gonna go and flip a variable in your extremely obfuscated, transpiled javascript code generated by your bundler, and even if they did find a place to flip a variable, the code would probably throw an error anyway.
You could lazy load that certain page as well once authenticated, then the code for it it wouldn't even be loaded into the users disk until they've successfully signed in.
I'm trying to reinforce some concepts learned in Colt Steele's Web Development Bootcamp and I have built a small website. At this time, I'm just trying to get the authentication working properly.
When a user signs up, I can see that they are added to my Mongo DB so I'm assuming that is working correctly but when I try to log back in it always redirects to the error page.
I have tried debugging this a number of ways and have compared it to the work we did in the course a hundred times but I cannot spot the bug with this. If anyone could give me some guidance I would really appreciate it.
Here's my project repo:
https://github.com/mcarre93/Depa
Ciao, according ti passport docs, when you post /login you should do:
app.post('/login', passport.authenticate('local'), function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
res.redirect('/account');
});
I read your code and you are doing something different. Try to modify your code as documentation suggest and let me know.
The Facebook, Google and Yahoo login for satellizer.js was pretty straight forward. All I had to do was create apps with their respective API's, configure them with my homepage's URL. Then I added the app-ids to the app.js file:
$authProvider.facebook({
clientId: 'xxxxxxxxxxxxxxxxx'
});
and lastly I added the app id and secret in the config.js file server-side.
I thought this would be the process with Twitter too, but their API keeps giving me an error saying
Something is technically wrong. Thanks for noticing—we're going to fix
it up and have things back to normal soon.
and no additional information is given, which leaves me with finding the needle in the haystack.
Are there any additional measures that I need to take to make the Twitter authentication work?
Be sure to set the right twitter secret and key.
I had the same problem until I rrealised that there was a space as the first character in the string of my twitter key.
This causes the same behavior you described
I currently have a set-up based on the meanjs stack boilerplate where I can have users logged in this state of being 'logged-in' stays as I navigate the URLs of the site. This is due to holding the user object in a Service which becomes globally available.
However this only works if I navigate from my base root, i.e. from '/' and by navigation only within my app.
If I manually enter a URL such as '/page1' it loses the global user object, however if I go to my root homepage and navigate to '/page1' via the site. Then it's fine, it sees the global user object in the Service object.
So I guess this happens due to the full page refresh which loses the global value where is navigating via the site does not do a refresh so you keep all your variables.
Some things to note:
I have enabled HTML5Mode, using prefix of '!'.
I use UI-Router
I use a tag with '/'
I have a re-write rule on express that after loading all my routes, I have one last route that takes all '/*' to and sends back the root index.html file, as that is where the angularjs stuff is.
I'm just wondering what people generally do here? Do they revert the standard cookies and local storage solutions? I'm fairly new to angular so I am guessing there are libraries out there for this.
I just would like to know what the recommended way to deal with this or what the majority do, just so I am aligned in the right way and angular way I suppose.
Update:
If I manually navigate to another URL on my site via the address bar, I lose my user state, however if I manually go back to my root via the address bar, my user state is seen again, so it is not simply about loosing state on window refresh. So it seems it is related to code running on root URL.
I have an express re-write that manually entered URLs (due to HTML5 Location Mode) should return the index.html first as it contains the AngularJs files and then the UI-Route takes over and routes it properly.
So I would have expected that any code on the root would have executed anyway, so it should be similar to navigating via the site or typing in the address bar. I must be missing something about Angular that has this effect.
Update 2
Right so more investigation lead me to this:
<script type="text/javascript">
var user = {{ user | json | safe }};
</script>
Which is a server side code for index.html, I guess this is not run when refreshing the page to a new page via a manual URL.
Using the hash bang mode, it works, which is because with hash bang mode, even I type a URL in the browser, it does not cause a refresh, where as using HTML5 Mode, it does refresh. So right now the solution I can think of is using sessionStorage.
Unless there better alternatives?
Update 3:
It seems the best way to handle this when using HTML5Mode is that you just have to have a re-write on the express server and few other things.
I think you have it right, but you may want to look at all the routes that your app may need and just consider some basic structure (api, user, session, partials etc). It just seems like one of those issues where it's as complicated as you want to let it become.
As far as the best practice you can follow the angular-fullstack-generator or the meanio project.
What you are doing looks closest to the mean.io mostly because they also use the ui-router, although they seem to have kept the hashbang and it looks like of more of an SEO friendly with some independant SPA page(s) capability.
You can probably install it and find the code before I explained it here so -
npm install -g meanio
mean init name
cd [name] && npm install
The angular-fullstack looks like this which is a good example of a more typical routing:
// Server API Routes
app.route('/api/awesomeThings')
.get(api.awesomeThings);
app.route('/api/users')
.post(users.create)
.put(users.changePassword);
app.route('/api/users/me')
.get(users.me);
app.route('/api/users/:id')
.get(users.show);
app.route('/api/session')
.post(session.login)
.delete(session.logout);
// All undefined api routes should return a 404
app.route('/api/*')
.get(function(req, res) {
res.send(404);
});
// All other routes to use Angular routing in app/scripts/app.js
app.route('/partials/*')
.get(index.partials);
app.route('/*')
.get( middleware.setUserCookie, index.index);
The partials are then found with some regex for simplicity and delivered without rendering like:
var path = require('path');
exports.partials = function(req, res) {
var stripped = req.url.split('.')[0];
var requestedView = path.join('./', stripped);
res.render(requestedView, function(err, html) {
if(err) {
console.log("Error rendering partial '" + requestedView + "'\n", err);
res.status(404);
res.send(404);
} else {
res.send(html);
}
});
};
And the index is rendered:
exports.index = function(req, res) {
res.render('index');
};
In the end I did have quite a bit of trouble but managed to get it to work by doing few things that can be broken down in to steps, which apply to those who are using HTML5Mode.
1) After enabling HTML5Mode in Angular, set a re-write on your server so that it sends back your index.html that contains the Angular src js files. Note, this re-write should be at the end after your static files and normal server routes (e.g. after your REST API routes).
2) Make sure that angular routes are not the same as your server routes. So if you have a front-end state /user/account, then do not have a server route /user/account otherwise it will not get called, change your server-side route to something like /api/v1/server/route.
3) For all anchor tags in your front-end that are meant to trigger a direct call to the server without having to go through Angular state/route, make sure you add a 'target=_self'.
Can I set up a multipage Node.js web server that does not require a unique route for every page?
I have a simple HTTP server set up using Node and Express, using EJS for view engine. My routing currently looks like this:
// routing
app.get('/', routes.index);
app.get('/hig', routes.hig);
app.get('/proto', routes.proto);
app.get('/design', routes.design);
app.get('/process', routes.process);
app.get('/demo', routes.demo);
app.get('/api', api.index);
app.get('/api/rules', api.list);
app.get('/api/rules/:id', api.ruleid);
I'd like to be able to easily update my site to have pages such as /hig/section1 and /hig/section2 (and so on) without having to update the route table each time and restart the server. More importantly, I'd like to be able to quickly and easily make multiple versions of a demo and be able to link to them.
For example, create a new demo and link a user to /demo/version23 while linking someone else to /demo/version 35, allowing me to illustrate different functionality without breaking previous demo sites. It would not be long until /demo/version108 and beyond exist, so having a sane way to create these without having 108+ routes is preferable.
The only method I've been successful at so far is updating route tables. Is there another way I can point to different pages in the route table that will allow me to more easily add new pages?
You should consider making part of url variable for ex as /hig/:section.
You should then get section as a parameter which you can use to map to different content, page or do any other logic that you want with that.
In my express api, I have a wildcard get. The endpoint var parses the keyword and then whatever you decided to do with that is up to you. In mine I have some if statements to change the database model etc but you don't need that... I would suggest keeping the 404 send, so if somebody hits an undesired url you can just give them whatever status code.
app.get('/:endpoint', function (req, res) {
var endpoint = req.params.endpoint;
if( endpoint == 'something' ){
} else if( endpoint == 'something' ){
} else { return res.send(404, { erorr: "That resource doesn't exist" }); }
// Display the results
});
I implemented simple demo project to achieve multi-app structure.
https://github.com/hitokun-s/node-express-multiapp-demo
With this structure, you can easily set up and maintain each app independently.
I hope this would be a help for you.