8000 Merge pull request #7 from loekiedepo/with-authentication · Lucky-Loek/Symfony-API-Example@98fe923 · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Dec 17, 2019. It is now read-only.

Commit 98fe923

Browse files
author
Loek van der Linde
authored
Merge pull request #7 from loekiedepo/with-authentication
With authentication
2 parents ab4256c + f7342ca commit 98fe923

25 files changed

+1577
-329
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
!var/logs/.gitkeep
1111
!/var/sessions
1212
/var/sessions/*
13+
!/var/jwt
1314
!var/sessions/.gitkeep
1415
!var/SymfonyRequirements.php
1516
/vendor/

.travis.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@ before_script:
99
- composer self-update
1010
- composer install --no-interaction
1111
- php bin/console doc:mig:mig --env=test --no-interaction
12+
- cat app/config/parameters.yml
13+
- php bin/console server:start
1214

1315
script:
1416
- vendor/bin/phpmd src/ text phpmd.xml
1517
- vendor/bin/phpcs --extensions=php --warning-severity=0 --report=full --standard=phpcs.xml src
1618
- vendor/bin/phpcpd --exclude src/AppBundle/Entity src
1719
- vendor/bin/phpunit --colors=auto
1820
- vendor/bin/behat --colors --format=pretty
21+
22+
after_script:
23+
- php bin/console server:stop

README.md

Lines changed: 97 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
# Symfony API Example
22

3-
[![Build Status](https://travis-ci.org/loekiedepo/Symfony-API-Example.svg?branch=master)](https://travis-ci.org/loekiedepo/Symfony-API-Example)
4-
[![StyleCI](https://styleci.io/repos/75643731/shield?branch=master)](https://styleci.io/repos/75643731)
3+
[![Build Status](https://travis-ci.org/loekiedepo/Symfony-API-Example.svg?branch=with-authentication)](https://travis-ci.org/loekiedepo/Symfony-API-Example)
4+
[![StyleCI](https://styleci.io/repos/75643731/shield?branch=with-authentication)](https://styleci.io/repos/75643731)
55

66
A small example of how an API could be written in Symfony. This project allow a user to receive/add/update/delete cars.
77

88
All output is standardized so that it is easy to parse in any language on any environment.
99

10+
This branch features an implementation of [JSON Web Tokens](https://jwt.io/) for authenticating users.
11+
1012
## Features
1113

14+
- JWT Authentication
15+
- [GET token](#get-a-token)
1216
- Data retrieval
1317
- [GET all entities](#get-all-entities)
1418
- [GET entity by id](#get-entity-by-id)
@@ -20,20 +24,23 @@ All output is standardized so that it is easy to parse in any language on any en
2024

2125
## URLS
2226

23-
```
24-
// GET
27+
```bash
28+
# POST retrieve a token
29+
symfony.app/api/token
30+
31+
# GET car
2532
symfony.app/car
2633

27-
// GET by id
34+
# GET car by id
2835
symfony.app/car/{id}
2936

30-
// POST new
37+
# POST new car
3138
symfony.app/car
3239

33-
// PATCH update
40+
# PATCH update car
3441
symfony.app/car/{id}
3542

36-
// DELETE remove
43+
# DELETE remove car
3744
symfony.app/car/{id}
3845
```
3946

@@ -50,23 +57,62 @@ symfony.app/car/{id}
5057
1. Clone this repo
5158
2. Run `composer install`
5259
3. Run `php bin/console doc:mig:mig`
60+
4. Run `php bin/console doc:fixtures:load`
5361

5462
### Testing
5563

5664
1. Run `php bin/console doc:mig:mig --env=test`
57-
2. Run `composer test`
65+
2. Run `php bin/console doc:fixtures:load --env=test`
66+
3. Run `composer test`
5867

59-
For more information which tests are run, please refer to the `"test"` section of `composer.json`
68+
For more information which tests are run, please refer to the `"test"` section of `composer.json`.
69+
You can run the given tests separately, i.e. `composer behat` or `composer phpunit`
6070

6171
## Technical Docs
6272

73+
### Error messages
74+
75+
All error messages have the same format, so they can be easily parsed in any language:
76+
77+
```JSON
78+
{
79+
"error": {
80+
"code": 401,
81+
"message": "Not privileged to request the resource."
82+
}
83+
}
84+
```
85+
86+
### GET a token
87+
88+
#### Request
89+
```bash
90+
$ curl --request POST \
91+
--url http://symfony.app/api/token \
92+
--header 'password: unsafepassword' \
93+
--header 'username: admin'
94+
```
95+
96+
#### Response
97+
```JSON
98+
{
99+
"token": "eyJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNDg0NTgyNTc4LCJpYXQiOjE0ODQ1ODE5Nzh9.t31C2jYVHWybZ2szEFwkGEzspYFyg9BlTyolnYtznnm8eFPIZI00hZPYCPFX2Ka7-gBFb3keM_2WVhfXKvreQpaFzge2HQ1lfMgVBCCUsxoiESUo6qCkna0Vb6ttv1qLyBRAqui_ijjANaAqEgO648vnIP0BMOYkjzw9-jNJNRQ25Bv4Y7bc_LGcGJQc2wGlg5sxWqMYhHwwCncBNPpdwTj9e9WULGBv0U1Hc_8I5eCrQFrCJGeQaKnEiy1GKXdRCSqwfCqEDrbXhgkBGygUbPGAYrfU8SnrtxFRI_EN92PByo2rjpy_M5gL-Md6czN5xDSxJHmswValR-I1ga1WkqEf194erD7KJmRRXUpz1HwNDWPDm1RJfzVgj0vTlW7kCKdLqGkkvaVnPuToxLhAPnp-kfdFkprtND0J8CajdiKaYVia4DwOjK4w_lbnfLMzZp6s6o7eKQ4h7_vkZAGu_DA0f6fVOuGQc5cqef_1oMqbKKrhVWL4xMg9wovpkAm_AF-iii-cjaXejArKzZ_4sKku5fc7BleSIHH0sXXLWlE_bI6ftc3AAxTl1buIOwpqrKDwlU_YfO8d9YkuZCRG-I0B8Nu0hfW6qh3jwIaqlqaAP6ZqAfAk8Sd6cQw8eqSqjhFjtSKA2J-DYn4lP2DC-0-_6ydj8sl3pB-DV7MEVVI"
100+
}
101+
```
102+
63103
### GET all entities
64-
```shell
65-
# Request
104+
105+
#### Request
106+
107+
```bash
66108
$ curl --request GET \
67-
--url http://symfony.app/car
68-
69-
# Response
109+
--url http://symfony.app/car \
110+
--header 'Authorization: Bearer {token}'
111+
```
112+
113+
#### Response
114+
115+
```JSON
70116
[
71117
{
72118
"id": 1,
@@ -85,12 +131,17 @@ $ curl --request GET \
85131
```
86132

87133
### GET entity by id
88-
```shell
89-
# Request
134+
135+
#### Request
136+
137+
```bash
90138
$ curl --request GET \
91-
--url http://symfony.app/car/1
92-
93-
# Response
139+
--url http://symfony.app/car/{id} \
140+
--header 'Authorization: Bearer {token}'
141+
```
142+
143+
#### Response
144+
```JSON
94145
{
95146
"id": 1,
96147
"brand": "Ford",
@@ -100,18 +151,23 @@ $ curl --request GET \
100151
```
101152

102153
### POST new entity
103-
```shell
104-
# Request
154+
155+
#### Request
156+
157+
```bash
105158
$ curl --request POST \
106159
--url http://symfony.app/car \
107160
--header 'content-type: application/json' \
161+
--header 'Authorization: Bearer {token}'
108162
--data '{
109163
"brand": "Ford",
110164
"name": "Mustang",
111165
"year": 1972
112166
}'
113-
114-
# Response
167+
```
168+
169+
#### Response
170+
```JSON
115171
{
116172
"id": 1,
117173
"brand": "Ford",
@@ -121,16 +177,20 @@ $ curl --request POST \
121177
```
122178

123179
### PATCH update existing entity
124-
```shell
125-
# Request
180+
181+
#### Request
182+
```bash
126183
$ curl --request PATCH \
127-
--url http://symfony.app/car/1 \
184+
--url http://symfony.app/car/{id} \
128185
--header 'content-type: application/json' \
186+
--header 'Authorization: Bearer {token} \
129187
--data '{
130188
"year": 2016
131189
}'
132-
133-
# Response
190+
```
191+
192+
#### Response
193+
```JSON
134194
{
135195
"id": 1,
136196
"brand": "Ford",
@@ -140,12 +200,16 @@ $ curl --request PATCH \
140200
```
141201
142202
### DELETE remove existing entity
143-
```shell
144-
# Request
203+
204+
#### Request
205+
```bash
145206
$ curl --request DELETE \
146-
--url http://symfony.app/car/1
207+
--url http://symfony.app/car/{id} \
208+
--header 'Authorization: Bearer {token}
209+
```
147210

148-
# Response
211+
#### Response
212+
```JSON
149213
{
150214
"message": "Car deleted"
151215
}

app/AppKernel.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public function registerBundles()
2020
new \JMS\SerializerBundle\JMSSerializerBundle(),
2121
new \Nelmio\CorsBundle\NelmioCorsBundle(),
2222
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
23+
new Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle(),
2324
];
2425

2526
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Application\Migrations;
4+
5+
use Doctrine\DBAL\Migrations\AbstractMigration;
6+
use Doctrine\DBAL\Schema\Schema;
7+
8+
/**
9+
* Auto-generated Migration: Please modify to your needs!
10+
*/
11+
class Version20170116124527 extends AbstractMigration
12+
{
13+
/**
14+
* @param Schema $schema
15+
*/
16+
public function up(Schema $schema)
17+
{
18+
// this up() migration is auto-generated, please modify it to your needs
19+
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
20+
21+
$this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_8D93D649F85E0677 (username), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
22+
}
23+
24+
/**
25+
* @param Schema $schema
26+
*/
27+
public function down(Schema $schema)
28+
{
29+
// this down() migration is auto-generated, please modify it to your needs
30+
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
31+
32+
$this->addSql('DROP TABLE user');
33+
}
34+
}

app/config/config.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,9 @@ fos_rest:
9292
view_response_listener: 'force'
9393
formats:
9494
json: true
95+
96+
lexik_jwt_authentication:
97+
private_key_path: '%jwt_private_key_path%'
98+
public_key_path: '%jwt_public_key_path%'
99+
pass_phrase: '%jwt_key_pass_phrase%'
100+
token_ttl: '%jwt_token_ttl%'

app/config/parameters.yml.dist

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
# Set parameters here that may be different on each deployment target of the app, e.g. development, staging, production.
33
# http://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
44
parameters:
5+
app_url: http://localhost:8000
56
database_host: 127.0.0.1
6-
database_port: ~
7-
database_name: symfony
7+
database_port: 3306
8+
database_name: symfony_test
89
database_user: root
910
database_password: ~
1011
# You should uncomment this if you want use pdo_sqlite
@@ -17,3 +18,8 @@ parameters:
1718

1819
# A secret key that's used to generate certain security-related tokens
1920
secret: ThisTokenIsNotSoSecretChangeIt
21+
22+
jwt_private_key_path: '%kernel.root_dir%/../var/jwt/private.pem'
23+
jwt_public_key_path: '%kernel.root_dir%/../var/jwt/public.pem'
24+
jwt_key_pass_phrase: symfony_test
25+
jwt_token_ttl: 600

app/config/security.yml

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,16 @@
22
# http://symfony.com/doc/current/security.html
33
security:
44

5+
encoders:
6+
AppBundle\Entity\User:
7+
algorithm: bcrypt
8+
59
# http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
610
providers:
7-
in_memory:
8-
memory: ~
11+
database_provider:
12+
entity:
13+
class: AppBundle:User
14+
property: username
915

1016
firewalls:
1117
# disables authentication for assets and the profiler, adapt it according to your needs
@@ -14,11 +20,10 @@ security:
1420
security: false
1521

1622
main:
17-
anonymous: ~
18-
# activate different ways to authenticate
19-
20-
# http_basic: ~
21-
# http://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
23+
pattern: ^/car
24+
anonymous: true
25+
stateless: true
2226

23-
# form_login: ~
24-
# http://symfony.com/doc/current/cookbook/security/form_login_setup.html
27+
guard:
28+
authenticators:
29+
- 'appbundle.jwt_token_authenticator'

app/config/services.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ services:
2929
arguments: ["@logger"]
3030
tags:
3131
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
32+
33+
appbundle.jwt_token_authenticator:
34+
class: AppBundle\Security\JwtTokenAuthenticator
35+
arguments: ["@lexik_jwt_authentication.encoder", "@doctrine.orm.entity_manager"]

behat.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ default:
33
Behat\Symfony2Extension: ~
44
Sanpi\Behatch\Extension: ~
55
Behat\MinkExtension:
6-
base_url: http://symfony.app
76
sessions:
87
default:
98
symfony2: ~

composer.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"nelmio/cors-bundle": "^1.4",
2828
"webmozart/assert": "^1.2",
2929
"doctrine/doctrine-migrations-bundle": "^1.2",
30-
"behat/mink-browserkit-driver": "^1.3"
30+
"guzzlehttp/guzzle": "^6.2",
31+
"lexik/jwt-authentication-bundle": "^2.1"
3132
},
3233
"require-dev": {
3334
"sensio/generator-bundle": "^3.0",
@@ -40,7 +41,8 @@
4041
"behat/symfony2-extension": "^2.1",
4142
"behatch/contexts": "^2.5",
4243
"doctrine/doctrine-fixtures-bundle": "^2.3",
43-
"sebastian/phpcpd": "^2.0"
44+
"sebastian/phpcpd": "^2.0",
45+
"behat/mink-browserkit-driver": "^1.3"
4446
},
4547
"scripts": {
4648
"symfony-scripts": [

0 commit comments

Comments
 (0)
0