Skip to content

Commit 3e2a421

Browse files
Implemented JWT authentication.
1 parent bba53ea commit 3e2a421

25 files changed

Lines changed: 1908 additions & 412 deletions

.idea/dictionaries/suraj.xml

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/workspace.xml

Lines changed: 244 additions & 155 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@
22

33
Flutter Wordpress API
44

5-
## Getting Started
5+
## Reqquirements
6+
- A Wordpress site using V2 REST API https://developer.wordpress.org/rest-api/
7+
- JWT Authentication for WP REST API V2 https://wordpress.org/plugins/jwt-authentication-for-wp-rest-api/
8+
- Flutter 1.0
69

7-
This project is a starting point for a Dart
8-
[package](https://flutter.io/developing-packages/),
9-
a library module containing code that can be shared easily across
10-
multiple Flutter or Dart projects.
1110

12-
For help getting started with Flutter, view our
13-
[online documentation](https://flutter.io/docs), which offers tutorials,
14-
samples, guidance on mobile development, and a full API reference.

example/lib/main.dart

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,40 @@ class PostsBuilder extends StatefulWidget {
5050
}
5151

5252
class PostsBuilderState extends State<PostsBuilder> {
53+
wp.WordPress wordPress;
5354
Future<List<wp.Posts>> posts;
55+
Future<List<wp.Users>> users;
5456

5557
@override
5658
void initState() {
5759
super.initState();
5860

59-
posts = wp.WordPressAPI().fetchPosts();
61+
wordPress = wp.WordPress(
62+
'https://wordpress.dsoft.website', wp.WordpressContext.view);
63+
64+
Future<wp.AuthResponse> auth = wordPress.authenticateUser(
65+
username: 'admin ', password: 'mypassword@123');
66+
67+
auth.then((response) {
68+
fetchPosts();
69+
}).catchError((err) {
70+
print(err.message);
71+
});
72+
73+
}
74+
75+
void fetchPosts()
76+
{
77+
setState(() {
78+
posts = wordPress.fetchPosts();
79+
});
80+
}
81+
82+
void fetchUsers()
83+
{
84+
setState(() {
85+
users = wordPress.fetchUsers();
86+
});
6087
}
6188

6289
@override
@@ -75,7 +102,8 @@ class PostsBuilderState extends State<PostsBuilder> {
75102
itemCount: snapshot.data.length,
76103
);
77104
} else if (snapshot.hasError) {
78-
return Text("${snapshot.error}");
105+
wp.WordpressError err = snapshot.error as wp.WordpressError;
106+
return Text(err.message);
79107
}
80108
return CircularProgressIndicator();
81109
},

flutter_wordpress.iml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<module type="JAVA_MODULE" version="4">
3+
<component name="FacetManager">
4+
<facet type="android" name="Android">
5+
<configuration>
6+
<option name="ALLOW_USER_CONFIGURATION" value="false" />
7+
</configuration>
8+
</facet>
9+
</component>
310
<component name="NewModuleRootManager" inherit-compiler-output="true">
411
<exclude-output />
512
<content url="file://$MODULE_DIR$">
613
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
714
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
15+
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
816
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
917
<excludeFolder url="file://$MODULE_DIR$/.idea" />
1018
<excludeFolder url="file://$MODULE_DIR$/.pub" />
@@ -13,7 +21,7 @@
1321
<excludeFolder url="file://$MODULE_DIR$/example/.pub" />
1422
<excludeFolder url="file://$MODULE_DIR$/example/build" />
1523
</content>
16-
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
24+
<orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
1725
<orderEntry type="sourceFolder" forTests="false" />
1826
<orderEntry type="library" name="Dart SDK" level="project" />
1927
<orderEntry type="library" name="Flutter Plugins" level="project" />

lib/flutter_wordpress.dart

Lines changed: 124 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,158 @@
1-
import 'dart:async';
1+
import 'dart:async' as async;
22
import 'dart:convert';
3-
import 'schemas/posts.dart';
3+
4+
import 'package:meta/meta.dart';
45
import 'package:http/http.dart' as http;
56

7+
import 'schemas/auth_response.dart';
8+
import 'schemas/avatar_urls.dart';
9+
import 'schemas/capabilities.dart';
10+
import 'schemas/categories.dart';
11+
import 'schemas/comments.dart';
12+
import 'schemas/content.dart';
13+
import 'schemas/error.dart';
14+
import 'schemas/excerpt.dart';
15+
import 'schemas/guid.dart';
16+
import 'schemas/labels.dart';
17+
import 'schemas/links.dart';
18+
import 'schemas/media.dart';
19+
import 'schemas/pages.dart';
20+
import 'schemas/post_statuses.dart';
21+
import 'schemas/post_types.dart';
22+
import 'schemas/posts.dart';
23+
import 'schemas/settings.dart';
24+
import 'schemas/tags.dart';
25+
import 'schemas/taxonomies.dart';
26+
import 'schemas/title.dart';
27+
import 'schemas/users.dart';
28+
29+
export 'schemas/auth_response.dart';
630
export 'schemas/avatar_urls.dart';
31+
export 'schemas/capabilities.dart';
732
export 'schemas/categories.dart';
833
export 'schemas/comments.dart';
934
export 'schemas/content.dart';
35+
export 'schemas/error.dart';
1036
export 'schemas/excerpt.dart';
1137
export 'schemas/guid.dart';
38+
export 'schemas/labels.dart';
1239
export 'schemas/links.dart';
1340
export 'schemas/media.dart';
1441
export 'schemas/pages.dart';
1542
export 'schemas/post_statuses.dart';
1643
export 'schemas/post_types.dart';
1744
export 'schemas/posts.dart';
45+
export 'schemas/settings.dart';
1846
export 'schemas/tags.dart';
1947
export 'schemas/taxonomies.dart';
2048
export 'schemas/title.dart';
2149
export 'schemas/users.dart';
2250

23-
class WordPressAPI {
24-
Future<List<Posts>> fetchPosts() async {
25-
final response =
26-
await http.get('http://demo.wp-api.org/wp-json/wp/v2/posts/');
51+
const URL_WP_BASE = '/wp-json/wp/v2';
52+
const URL_JWT_BASE = '/wp-json/jwt-auth/v1';
53+
54+
const URL_JWT_TOKEN = '$URL_JWT_BASE/token';
55+
const URL_JWT_TOKEN_VALIDATE = '$URL_JWT_BASE/token/validate';
56+
57+
const URL_POSTS = '$URL_WP_BASE/posts';
58+
const URL_USERS = '$URL_WP_BASE/users';
59+
60+
enum WordpressContext { view, embed, edit }
61+
62+
class WordPress {
63+
final String _baseUrl;
64+
final String _wpContext;
65+
66+
Map<String, String> _header = {
67+
'Authorization': 'Bearer ',
68+
};
69+
String _wpContextParam;
70+
71+
/// Take in base url and remove trailing '/' from the url if it exists.
72+
/// Take in the wordpress context and get the enum name.
73+
WordPress(String baseUrl, WordpressContext wpContext)
74+
: assert(baseUrl != null),
75+
this._baseUrl = baseUrl.endsWith('/')
76+
? baseUrl.substring(0, baseUrl.length - 1)
77+
: baseUrl,
78+
this._wpContext = wpContext.toString().split('.')[1] {
79+
_wpContextParam = '/?context=${this._wpContext}';
80+
}
81+
82+
async.Future<AuthResponse> authenticateUser(
83+
{@required username, @required password}) async {
84+
final body = {
85+
'username': username,
86+
'password': password,
87+
};
88+
89+
final response = await http.post(
90+
_baseUrl + URL_JWT_TOKEN,
91+
body: body,
92+
);
93+
94+
if (response.statusCode == 200) {
95+
AuthResponse authResponse =
96+
AuthResponse.fromJson(json.decode(response.body));
97+
_header['Authorization'] += authResponse.token;
98+
return authResponse;
99+
} else {
100+
try {
101+
WordpressError err =
102+
WordpressError.fromJson(json.decode(response.body));
103+
throw err;
104+
} catch (e) {
105+
throw new WordpressError(message: e.message);
106+
}
107+
}
108+
}
109+
110+
async.Future<List<Posts>> fetchPosts() async {
111+
final url = _baseUrl + URL_POSTS + _wpContextParam;
112+
113+
final response = await http.get(url, headers: _header);
27114

28115
if (response.statusCode == 200) {
29116
List<Posts> posts = new List();
30117

31118
dynamic list = json.decode(response.body);
32-
print('List lenght: ${list.length}');
33119
list.forEach((post) {
34120
posts.add(Posts.fromJson(post));
35121
});
36122
return posts;
123+
} else {
124+
try {
125+
WordpressError err =
126+
WordpressError.fromJson(json.decode(response.body));
127+
throw err;
128+
} catch (e) {
129+
throw new WordpressError(message: e.message);
130+
}
131+
}
132+
}
37133

134+
async.Future<List<Users>> fetchUsers() async {
135+
final url = _baseUrl + URL_USERS + _wpContextParam;
136+
137+
final response = await http.get(url, headers: _header);
138+
139+
if (response.statusCode == 200) {
140+
List<Users> users = new List();
141+
dynamic list = json.decode(response.body);
142+
list.forEach((user) {
143+
users.add(Users.fromJson(user));
144+
});
145+
return users;
38146
} else {
39-
throw Exception('Failed to load post');
147+
try {
148+
WordpressError err =
149+
WordpressError.fromJson(json.decode(response.body));
150+
throw err;
151+
} catch (e) {
152+
throw new WordpressError(message: e.message);
153+
}
40154
}
41155
}
156+
157+
42158
}

lib/schemas/auth_response.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
class AuthResponse {
2+
String token;
3+
String userEmail;
4+
String userNicename;
5+
String userDisplayName;
6+
7+
AuthResponse(
8+
{this.token, this.userEmail, this.userNicename, this.userDisplayName});
9+
10+
AuthResponse.fromJson(Map<String, dynamic> json) {
11+
token = json['token'];
12+
userEmail = json['user_email'];
13+
userNicename = json['user_nicename'];
14+
userDisplayName = json['user_display_name'];
15+
}
16+
17+
Map<String, dynamic> toJson() {
18+
final Map<String, dynamic> data = new Map<String, dynamic>();
19+
data['token'] = this.token;
20+
data['user_email'] = this.userEmail;
21+
data['user_nicename'] = this.userNicename;
22+
data['user_display_name'] = this.userDisplayName;
23+
return data;
24+
}
25+
}

lib/schemas/capabilities.dart

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
class Capabilities {
2+
String manageTerms;
3+
String editTerms;
4+
String deleteTerms;
5+
String assignTerms;
6+
String editPost;
7+
String readPost;
8+
String deletePost;
9+
String editPosts;
10+
String editOthersPosts;
11+
String publishPosts;
12+
String readPrivatePosts;
13+
String read;
14+
String deletePosts;
15+
String deletePrivatePosts;
16+
String deletePublishedPosts;
17+
String deleteOthersPosts;
18+
String editPrivatePosts;
19+
String editPublishedPosts;
20+
String createPosts;
21+
22+
Capabilities({
23+
this.manageTerms,
24+
this.editTerms,
25+
this.deleteTerms,
26+
this.assignTerms,
27+
this.editPost,
28+
this.readPost,
29+
this.deletePost,
30+
this.editPosts,
31+
this.editOthersPosts,
32+
this.publishPosts,
33+
this.readPrivatePosts,
34+
this.read,
35+
this.deletePosts,
36+
this.deletePrivatePosts,
37+
this.deletePublishedPosts,
38+
this.deleteOthersPosts,
39+
this.editPrivatePosts,
40+
this.editPublishedPosts,
41+
this.createPosts,
42+
});
43+
44+
Capabilities.fromJson(Map<String, dynamic> json) {
45+
manageTerms = json['manage_terms'];
46+
editTerms = json['edit_terms'];
47+
deleteTerms = json['delete_terms'];
48+
assignTerms = json['assign_terms'];
49+
editPost = json['edit_post'];
50+
readPost = json['read_post'];
51+
deletePost = json['delete_post'];
52+
editPosts = json['edit_posts'];
53+
editOthersPosts = json['edit_others_posts'];
54+
publishPosts = json['publish_posts'];
55+
readPrivatePosts = json['read_private_posts'];
56+
read = json['read'];
57+
deletePosts = json['delete_posts'];
58+
deletePrivatePosts = json['delete_private_posts'];
59+
deletePublishedPosts = json['delete_published_posts'];
60+
deleteOthersPosts = json['delete_others_posts'];
61+
editPrivatePosts = json['edit_private_posts'];
62+
editPublishedPosts = json['edit_published_posts'];
63+
createPosts = json['create_posts'];
64+
}
65+
66+
Map<String, dynamic> toJson() {
67+
final Map<String, dynamic> data = new Map<String, dynamic>();
68+
data['manage_terms'] = this.manageTerms;
69+
data['edit_terms'] = this.editTerms;
70+
data['delete_terms'] = this.deleteTerms;
71+
data['assign_terms'] = this.assignTerms;
72+
data['edit_post'] = this.editPost;
73+
data['read_post'] = this.readPost;
74+
data['delete_post'] = this.deletePost;
75+
data['edit_posts'] = this.editPosts;
76+
data['edit_others_posts'] = this.editOthersPosts;
77+
data['publish_posts'] = this.publishPosts;
78+
data['read_private_posts'] = this.readPrivatePosts;
79+
data['read'] = this.read;
80+
data['delete_posts'] = this.deletePosts;
81+
data['delete_private_posts'] = this.deletePrivatePosts;
82+
data['delete_published_posts'] = this.deletePublishedPosts;
83+
data['delete_others_posts'] = this.deleteOthersPosts;
84+
data['edit_private_posts'] = this.editPrivatePosts;
85+
data['edit_published_posts'] = this.editPublishedPosts;
86+
data['create_posts'] = this.createPosts;
87+
return data;
88+
}
89+
}

0 commit comments

Comments
 (0)