I'm trying to create a system which keeps the user logged in (something like remember me checked). Ok I have a table like this:
// cookies
+---------+-------------------------+------------------+------------+------------+
| id | email | cookie | date_time | device |
+---------+-------------------------+------------------+------------+------------+
| int(11) | varchar(50) | varchar(128) | int(11) | |
+---------+-------------------------+------------------+------------+------------+
| 1 | jack_2009#gmail.com | ojer0f934mf2... | 1467204523 | |
| 2 | peter.zm#yahoo.com | ko4398f43043... | 1467205521 | |
| 3 | matrix_john23#gmail.com | 34fjkg3j438t... | 1467205601 | |
| 4 | peter.zm#yahoo.com | 0243hfd348i4... | 1467206039 | |
+---------+-------------------------+------------------+------------+------------+
As you see, this user peter.zm#yahoo.com have logged in by two different devices:
| 2 | peter.zm#yahoo.com | ko4398f43043... | 1467205521 | |
| 4 | peter.zm#yahoo.com | 0243hfd348i4... | 1467206039 | |
So email column isn't unique and each device has its own row.
My question: How can I fill device column?
Why do I need to determine devices? Because when an user removes his browser's cookies, then my website identifies him as a new user and creates a new row for him into table above. So after a while, there will be some redundant rows in the table.
For example: Imagine peter has just two devices (laptop, phone). And he have two rows into table above. Ok, he removes his browser's cookies and logs in. What happens? My website creates a new row into table above. Now peter has 3 rows into table above (while he has just two devices). So surely one of those three rows is redundant. That's why I need to detect devices to remove redundant rows.
How about with the User Agent string from their last interaction with your application?
As an additional defence-in-depth security measure, you could also validate that the user agent matches their previously used one for this device in order to mitigate session hijacking. Be aware that any browser or OS upgrades will invalidate the "remember-me" on that device though.
As a side note, you are better off keying on a unique ID rather than email address because that way it is much easier to update a user's email should you need to in future.
Use the web authn api or the credentials api
Related
Im building web app which include user authentification, so every user will have profile with personal data. Data will be stored in db, but due to their privacy users can choose which of their informations will be displayed to public visitors. Let say someone want to hide his phone number from others, so he will go to account setings and choose "hide" option. But I cant figure out how to make it with db and rest of app.
Any guidance or reference will be helpfull. Thanks
Make your table look like something like this. This means that John and Laura have different privacy settings than Jane and sam.
+-------+------------+------------+--------+
| user | phone | address | hidden |
+-------+------------+------------+--------+
| john | 2025550165 | example 1 | 1 |
| jane | 2026118043 | example 2 | 0 |
| sam | 2026682607 | example 3 | 0 |
| laura | 2026688273 | example 4 | 1 |
+-------+------------+------------+--------+
To use this, the SQL would be something like: SELECT user, phone, address from table where hidden = 0
which would return only jane and sam.
Does this help at all?
You can create some table like user_settings where user can set what fields should not be visible to public
I have created a privilege system for my application which allows/disallows access to specific pages based on user input.
The table looks something like this:
page_id | client_id | sys_group_no | name | friendly_name | viewable |
1 | 4 | 1 | home | Home | true |
2 | 4 | 1 | admin| Admin Home | false |
So if the user in client_id 4 is of group 1 they are NOT allowed to view 'Admin Home' it isn't actually quite this simple but for the sake of this question we can pretend.
The problem is as maintenance goes on this table get out of date quickly, and when you have a few thousand rows, constantly checking the table against the actual page names (using scandir() and array_diff()) will be expensive. Is there a different paradigm for checking this kind of integrity other than direct comparison? - For instance would hashing my $page_array and comparing it be a better approach?
OK, Last post on this subject (I hope). I've been trying to look into normalisation for tables in a website that I've been building and I have to be honest that I've struggled with it, however after my last post it seems that I may have finally grasped it and set my tables properly.
However, one question remains. If I create a table that is seemingly in 3rd normal form, is it acceptable to have areas of white space or empty cells if the data is relevant to that specific table? Let me give you an example:
On a news website I have an Authors_Table
+----+-----------+----------+-----------------+-------------------+---------+----------+---------+
| ID | FIRSTNAME | SURNAME | EMAIL | BIO ( REQUIRED ) | TWITTER | FACEBOOK | WEBSITE |
+----+-----------+----------+-----------------+-------------------+---------+----------+---------+
| 01 | Brian | Griffin | brian#gmail.com | About me... | URL | | URL |
| 02 | Meg | Griffin | meg#gmail.com | About me... | URL | | |
| 03 | Peter | Griffin | peter#gmail.com | About me... | | URL | URL |
| 04 | Glen | Quagmire | glen#gmail.com | About me... | URL | URL | |
+----+-----------+----------+-----------------+-------------------+---------+----------+---------+
This would be used on the article page to give a little details about who has written it, which is very common in newspapers and on modern blogs. Now the last 3 columns Facebook, Twitter, Website are obviously relevant to the Author & therefore to the PK (ID). As you know though, not everyone has either twitter or a wesbite or facebook so the content of these cells is rather flexible so obviously empty cells will occur in some cases.
It was suggested to do it another way so I produced:
Links
+----+-------------------+
| ID | TYPE |
+----+-------------------+
| 01 | Facebook |
| 02 | Twitter |
| 03 | Website |
+----+-------------------+
Author_Links
+----------+--------+------+
| AUTHOR | TYPE | LINK |
+----------+--------+------+
| 01 | 01 | URL |
| 01 | 02 | URL |
| 01 | 03 | URL |
| 02 | 02 | URL |
| 02 | 03 | URL |
| 03 | 01 | URL |
+----------+--------+------+
Now I understand the concept of this however isn't it just as "correct" to have and to use the original table. Updates can be made using a form & php to say:
$update_link_sql = "UPDATE authours SET facebook = ' NEW VALUE ' WHERE id = '$author_id'";
$update_link_res = mysqli_query($con, $update_links_sql);
As for me Authors_Table is correct.
| ID | FIRSTNAME | SURNAME | EMAIL | BIO ( REQUIRED ) | TWITTER | FACEBOOK | WEBSITE |
The only reason to have three tables:
Authors
| ID | FIRSTNAME | SURNAME | EMAIL | BIO ( REQUIRED ) |
Link_types
| ID | TYPE |
Author_links
| AUTHOR_ID | LINK_TYPE_ID | URL |
...is that your authors could have more than one link of specific type (for example two twitter accounts, btw, is it legal?)
If we suppose that any author can have no more than one account of each type - your version with single table is correct.
Either way is acceptable depending on functional requirements.
If you need to dynamically add more url types/fields to profile then use latter.
If there is ever going to be only 3 then former is better.
No need to over-engineer.
Yes, it's "correct" to store "optional" attributes as columns in the entity table. It's just when we have repeated values, e.g. multiple facebook pages for an author, for example, that we'd want to implement the child table. (We don't want to store "repeating" attributes in the entity table.)
As long as there's a restriction in the model, that an attribute will be limited to a single value (a single facebook page, a single twitter, etc.) those attributes can be stored in the entity table. We'd just use a NULL value to indicate that a value is not present.
One benefit of the separate table approach (outlined in your post) is that it would be "easier" to add a new "type" of URL. For example, if in the future we want to store a blogspot URL, or an instagram URL, instead of having to modify the entity table to add new columns, we can simply add rows to the "link_type" table and "author_link" table. That's the big benefit there.
Recently I have been planning a system that allows a user to customize and add to a web interface. The app could be compared to a quiz creating system. The problem I'm having is how to design a schema that will allow for "variable" numbers of additions to be made to the application.
The first option that I looked into was just creating an object for the additions and then serializing it and putting it in its own column. The content wouldn't be edited often so writing would be minimal, reads however would be very often. (caching could be used to cut down)
The other option was using something other than mysql or postgresql such as cassandra. I've never used other databases before but would be interested in learning how to use them if they would improve the design of the system.
Any input on the subject would be appreciated.
Thank you.
*edit 29/3/14
Some information on the data being changed. For my idea above of using a serialized object, you could say that in the table I would store the name of the quiz, the number of points the quiz is worth and then a column called quiz data that would store the serialized object containing the information on the questions. So overall the object could look like this:
Questions(Array):{
[1](Object):Question{
Field-type(int):1
Field-title(string):"Whats your gender?"
Options(Array):{"Female", "Male"}
}
[2](Object):Question{
Field-type(int):2
Field-title(string):"Whats your name?"
}
}
The structure could vary of course but generally i would be storing integers to determin the type of field in the quiz and then a field to hold the label for the field and the options (if there are any) for that field.
In this scenario I would advise looking at MongoDB.
However if you want to work with MySQL you can think about the entity-attribute-value model in your design. The EAV model allows you to design for entries that contain a variable number of attributes.
edit
Following your update on the datatypes you would like to store, you could map your design as follows:
+-------------------------------------+
| QuizQuestions |
+----+---------+----------------------+
| id | type_id | question_txt |
+----+---------+----------------------+
| 1 | 1 | What's your gender? |
| 2 | 2 | What's your name? |
+----+---------+----------------------+
+-----------------------------------+
| QuestionTypes |
+----+--------------+---------------+
| id | attribute_id | description |
+----+--------------+---------------+
| 1 | 1 | Single select |
| 2 | 2 | Free text |
+----+--------------+---------------+
+----------------------------+
| QuestionValues |
+----+--------------+--------+
| id | question_id | value |
+----+--------------+--------+
| 1 | 1 | Male |
| 2 | 1 | Female |
+----+--------------+--------+
+-------------------------------+
| QuestionResponses |
+----+--------------+-----------+
| id | question_id | response |
+----+--------------+-----------+
| 1 | 1 | 1 |
| 2 | 2 | Fred |
+----+--------------+-----------+
This would then allow you to dynamically add various different questions (QuizQuestions), of different types (QuestionTypes), and then restrict them with different options (QuestionValues) and store those responses (QuestionResponses).
My website provide the user to create an account and log in with facebook. The user table contain: userId (generated by $userId = uniqid(rand(), true;, if user creating his own account). password, salt, email, date joined.
1st question:
I am not sure if what I am doing with facebook is safe. Right now I am getting user ID from facebook and sending it to server with xmlhttpRequest object. Then server store it under userID and leave other columns blank.
2nd question:
Is the possibilities significant for the facebook userID to overlap with normal account's userid generated by uniquid(rand(), true)
3rd question:
is it safe to use client side login? I mean even my App ID will be seen by users.
4th question:
In order to tell if the entry is a facebook account or normal account, should I add another column in database, true=facebook account, false=normal account. Or should I just check to see if password column is blank for the certain account?
Using thepointless.com as an example, every user gets an auto-incremented ID, including facebook users. External authentication services are recognized by the username, which contains a URL for "irregular" users:
+----------+------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------------+------+-----+-------------------+----------------+
| user_id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| username | varchar(255) | YES | UNI | NULL | |
| password | varchar(255) | YES | | NULL | |
| created | timestamp | NO | | CURRENT_TIMESTAMP | |
| userdata | mediumtext | YES | | NULL | |
| admin | tinyint(1) | YES | | 0 | |
| name | varchar(765) | YES | | NULL | |
+----------+------------------+------+-----+-------------------+----------------+
Facebook users' usernames are the URLs of their graph data, like http://graph.facebook.com/8643372. It isn't necessary in your system to point to something real, so long as it identifies the domain and an external [unique] ID. It just so happens in this case that the user's public graph object is a short, predictable URL.
Normal users are restricted from prefixing their usernames with http or https. The password is left blank. And the userdata stores the JSON or XML provided by the 3rd party authentication service.
A fully client-side login shouldn't generally be trusted by server-side logic. But, server-side validation of a JavaScript initiated login is generally not difficult. And there's no reason not to trust, at least on a preliminary basis, an entirely client-side authentication on the client.
And as far as I know, there's no need to keep your App ID a secret. It's your "App Secret" that needs to remain hidden.