|
8 | 8 | import io.vertx.ext.auth.oauth2.OAuth2Auth;
|
9 | 9 | import io.vertx.ext.auth.oauth2.providers.GithubAuth;
|
10 | 10 | import io.vertx.ext.web.Router;
|
11 |
| -import io.vertx.ext.web.RoutingContext; |
12 | 11 | import io.vertx.ext.web.handler.*;
|
13 | 12 | import io.vertx.ext.web.sstore.LocalSessionStore;
|
14 | 13 | import io.vertx.ext.web.templ.HandlebarsTemplateEngine;
|
|
18 | 17 | */
|
19 | 18 | public class Server extends AbstractVerticle {
|
20 | 19 |
|
21 |
| - private static final String CLIENT_ID = System.getenv("GH_BASIC_CLIENT_ID"); |
22 |
| - private static final String CLIENT_SECRET = System.getenv("GH_BASIC_SECRET_ID"); |
23 |
| - |
24 |
| - // In order to use a template we first need to create an engine |
25 |
| - private final HandlebarsTemplateEngine engine = HandlebarsTemplateEngine.create(); |
26 |
| - |
27 | 20 | // Convenience method so you can run it in your IDE
|
28 | 21 | public static void main(String[] args) {
|
29 | 22 | Runner.runExample(Server.class);
|
30 | 23 | }
|
31 | 24 |
|
32 |
| - private boolean isAuthenticated(RoutingContext ctx) { |
33 |
| - return ctx.user() != null; |
34 |
| - } |
| 25 | + // you should never store these in code, |
| 26 | + // these are your github application credentials |
| 27 | + private static final String CLIENT_ID = "xxxxxxxxxxxxxxxxxxxx"; |
| 28 | + private static final String CLIENT_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; |
35 | 29 |
|
36 |
| - private void authenticate(RoutingContext ctx) { |
37 |
| - // we pass the client id to the template |
38 |
| - ctx.put("client_id", CLIENT_ID); |
39 |
| - // and now delegate to the engine to render it. |
40 |
| - engine.render(ctx, "views", "/index.hbs", res -> { |
41 |
| - if (res.succeeded()) { |
42 |
| - ctx.response() |
43 |
| - .putHeader("Content-Type", "text/html") |
44 |
| - .end(res.result()); |
45 |
| - } else { |
46 |
| - ctx.fail(res.cause()); |
47 |
| - } |
48 |
| - }); |
49 |
| - } |
| 30 | + // In order to use a template we first need to create an engine |
| 31 | + private final HandlebarsTemplateEngine engine = HandlebarsTemplateEngine.create(); |
50 | 32 |
|
51 | 33 | @Override
|
52 | 34 | public void start() throws Exception {
|
53 | 35 | // To simplify the development of the web components we use a Router to route all HTTP requests
|
54 | 36 | // to organize our code in a reusable way.
|
55 | 37 | final Router router = Router.router(vertx);
|
56 |
| - // We need cookies, sessions and request bodies |
| 38 | + // We need cookies and sessions |
57 | 39 | router.route().handler(CookieHandler.create());
|
58 |
| - router.route().handler(BodyHandler.create()); |
59 | 40 | router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)));
|
60 | 41 | // Simple auth service which uses a GitHub to authenticate the user
|
61 | 42 | OAuth2Auth authProvider = GithubAuth.create(vertx, CLIENT_ID, CLIENT_SECRET);
|
62 | 43 | // We need a user session handler too to make sure the user is stored in the session between requests
|
63 | 44 | router.route().handler(UserSessionHandler.create(authProvider));
|
| 45 | + // we now protect the resource under the path "/protected" |
| 46 | + router.route("/protected").handler( |
| 47 | + OAuth2AuthHandler.create(authProvider) |
| 48 | + // we now configure the oauth2 handler, it will setup the callback handler |
| 49 | + // as expected by your oauth2 provider. |
| 50 | + .setupCallback(router.route("/callback")) |
| 51 | + // for this resource we require that users have the authority to retrieve the user emails |
| 52 | + .addAuthority("user:email") |
| 53 | + ); |
64 | 54 | // Entry point to the application, this will render a custom template.
|
65 | 55 | router.get("/").handler(ctx -> {
|
66 |
| - if (!isAuthenticated(ctx)) { |
67 |
| - authenticate(ctx); |
68 |
| - } else { |
69 |
| - AccessToken user = (AccessToken) ctx.user(); |
70 |
| - |
71 |
| - user.userInfo(res -> { |
72 |
| - if (res.failed()) { |
73 |
| - res.cause().printStackTrace(); |
74 |
| - // request didn't succeed because the token was revoked so we |
75 |
| - // invalidate the token stored in the session and render the |
76 |
| - // index page so that the user can start the OAuth flow again |
77 |
| - ctx.session().destroy(); |
78 |
| - authenticate(ctx); |
79 |
| - } else { |
80 |
| - // the request succeeded, so we check the list of current scopes |
81 |
| - JsonArray scopes = new JsonArray(); |
82 |
| - JsonObject userInfo = res.result(); |
83 |
| - |
84 |
| - if (userInfo.containsKey("X-OAuth-Scopes")) { |
85 |
| - for (String scope : userInfo.getString("X-OAuth-Scopes").split(", ")) { |
86 |
| - scopes.add(scope); |
87 |
| - } |
88 |
| - } |
89 |
| - |
90 |
| - if (scopes.contains("user:email")) { |
91 |
| - // fetch the user emails from the github API |
92 |
| - user.fetch("https://api.github.com/user/emails", res2 -> { |
93 |
| - if (res2.failed()) { |
94 |
| - res2.cause().printStackTrace(); |
95 |
| - // request didn't succeed because the token was revoked so we |
96 |
| - // invalidate the token stored in the session and render the |
97 |
| - // index page so that the user can start the OAuth flow again |
98 |
| - ctx.session().destroy(); |
99 |
| - authenticate(ctx); |
| 56 | + // we pass the client id to the template |
| 57 | + ctx.put("client_id", CLIENT_ID); |
| 58 | + // and now delegate to the engine to render it. |
| 59 | + engine.render(ctx, "views", "/index.hbs", res -> { |
| 60 | + if (res.succeeded()) { |
| 61 | + ctx.response() |
| 62 | + .putHeader("Content-Type", "text/html") |
| 63 | + .end(res.result()); |
| 64 | + } else { |
| 65 | + ctx.fail(res.cause()); |
| 66 | + } |
| 67 | + }); |
| 68 | + }); |
| 69 | + // The protected resource |
| 70 | + router.get("/protected").handler(ctx -> { |
| 71 | + AccessToken user = (AccessToken) ctx.user(); |
| 72 | + |
| 73 | + user.userInfo(res -> { |
| 74 | + if (res.failed()) { |
| 75 | + // request didn't succeed because the token was revoked so we |
| 76 | + // invalidate the token stored in the session and render the |
| 77 | + // index page so that the user can start the OAuth flow again |
| 78 | + ctx.session().destroy(); |
| 79 | + ctx.fail(res.cause()); |
| 80 | + } else { |
| 81 | + // the request succeeded, so we use the API to fetch the user's emails |
| 82 | + final JsonObject userInfo = res.result(); |
| 83 | + |
| 84 | + // fetch the user emails from the github API |
| 85 | + user.fetch("https://api.github.com/user/emails", res2 -> { |
| 86 | + if (res2.failed()) { |
| 87 | + // request didn't succeed because the token was revoked so we |
| 88 | + // invalidate the token stored in the session and render the |
| 89 | + // index page so that the user can start the OAuth flow again |
| 90 | + ctx.session().destroy(); |
| 91 | + ctx.fail(res2.cause()); |
| 92 | + } else { |
| 93 | + userInfo.put("private_emails", res2.result().jsonArray()); |
| 94 | + // we pass the client info to the template |
| 95 | + ctx.put("userInfo", userInfo); |
| 96 | + // and now delegate to the engine to render it. |
| 97 | + engine.render(ctx, "views", "/advanced.hbs", res3 -> { |
| 98 | + if (res3.succeeded()) { |
| 99 | + ctx.response() |
| 100 | + .putHeader("Content-Type", "text/html") |
| 101 | + .end(res3.result()); |
100 | 102 | } else {
|
101 |
| - userInfo.put("private_emails", res2.result().jsonArray()); |
102 |
| - |
103 |
| - // we pass the client id to the template |
104 |
| - ctx.put("userInfo", userInfo); |
105 |
| - |
106 |
| - // and now delegate to the engine to render it. |
107 |
| - engine.render(ctx, "views", "/advanced.hbs", res3 -> { |
108 |
| - if (res3.succeeded()) { |
109 |
| - ctx.response() |
110 |
| - .putHeader("Content-Type", "text/html") |
111 |
| - .end(res3.result()); |
112 |
| - } else { |
113 |
| - ctx.fail(res3.cause()); |
114 |
| - } |
115 |
| - }); |
| 103 | + ctx.fail(res3.cause()); |
116 | 104 | }
|
117 | 105 | });
|
118 | 106 | }
|
119 |
| - |
120 |
| - } |
121 |
| - }); |
122 |
| - } |
| 107 | + }); |
| 108 | + } |
| 109 | + }); |
123 | 110 | });
|
124 |
| - // the callback url |
125 |
| - OAuth2AuthHandler oauth2Handler = OAuth2AuthHandler.create(authProvider, "http://localhost:8080/callback"); |
126 |
| - oauth2Handler.setupCallback(router.route("/callback")); |
127 | 111 |
|
128 | 112 | vertx.createHttpServer().requestHandler(router::accept).listen(8080);
|
129 | 113 | }
|
130 | 114 | }
|
131 |
| - |
0 commit comments