In this section, you’ll modify the simple app you just built by adding an explicit link to login with GitHub. Instead of being redirected immediately, the new link will be visible on the home page, and the user can choose to login or to stay unauthenticated. Only when the user has clicked on the link will the secure content be rendered.
To render content on the condition that the user is authenticated, you have the option of either server-side or client-side rendering.
Here, you’ll change the client side with JQuery, though if you prefer to use something else, it shouldn’t be very hard to translate the client code.
To get started with the dynamic content, you need to mark a couple of HTML elements like so:
<div class="container unauthenticated">
With GitHub: <a href="/oauth2/authorization/github">click here</a>
</div>
<div class="container authenticated" style="display:none">
Logged in as: <span id="user"></span>
</div>
By default, the first <div>
will show, and the second one won’t.
Note also the empty <span>
with an id
attribute.
In a moment, you’ll add a server-side endpoint that will return the logged in user details as JSON.
But, first, add the following JavaScript, which will hit that endpoint.
Based on the endpoint’s response, this JavaScript will populate the <span>
tag with the user’s name and toggle the <div>
appropriately:
<script type="text/javascript">
$.get("/user", function(data) {
$("#user").html(data.name);
$(".unauthenticated").hide()
$(".authenticated").show()
});
</script>
Note that this JavaScript expects the server-side endpoint to be called /user
.
Now, you’ll add the server-side endpoint just mentioned, calling it /user
.
It will send back the currently logged-in user, which we can do quite easily in our main class:
@SpringBootApplication
@RestController
public class SocialApplication {
@GetMapping("/user")
public Map<String, Object> user(@AuthenticationPrincipal OAuth2User principal) {
return Collections.singletonMap("name", principal.getAttribute("name"));
}
public static void main(String[] args) {
SpringApplication.run(SocialApplication.class, args);
}
}
Note the use of @RestController
, @GetMapping
, and the OAuth2User
injected into the handler method.
Warning
|
It’s not a great idea to return a whole OAuth2User in an endpoint since it might contain information you would rather not reveal to a browser client.
|
There’s one final change you’ll need to make.
This app will now work fine and authenticate as before, but it’s still going to redirect before showing the page.
To make the link visible, we also need to switch off the security on the home page by extending WebSecurityConfigurerAdapter
:
@SpringBootApplication
@RestController
public class SocialApplication extends WebSecurityConfigurerAdapter {
// ...
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(a -> a
.antMatchers("/", "/error", "/webjars/**").permitAll()
.anyRequest().authenticated()
)
.exceptionHandling(e -> e
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
)
.oauth2Login();
// @formatter:on
}
}
Spring Boot attaches special meaning to a WebSecurityConfigurerAdapter
on the class annotated with @SpringBootApplication
:
It uses it to configure the security filter chain that carries the OAuth 2.0 authentication processor.
The above configuration indicates a whitelist of permitted endpoints, with every other endpoint requiring authentication.
You want to allow:
-
/
since that’s the page you just made dynamic, with some of its content visible to unauthenticated users -
/error
since that’s a Spring Boot endpoint for displaying errors, and -
/webjars/**
since you’ll want your JavaScript to run for all visitors, authenticated or not
You won’t see anything about /user
in this configuration, though.
Everything, including /user
remains secure unless indicated because of the .anyRequest().authenticated()
configuration at the end.
Finally, since we are interfacing with the backend over Ajax, we’ll want to configure endpoints to respond with a 401 instead of the default behavior of redirecting to a login page.
Configuring the authenticationEntryPoint
achieves this for us.
With those changes in place, the application is complete, and if you run it and visit the home page you should see a nicely styled HTML link to "login with GitHub". The link takes you not directly to GitHub, but to the local path that processes the authentication (and sends a redirect to GitHub). Once you have authenticated, you get redirected back to the local app, where it now displays your name (assuming you have set up your permissions in GitHub to allow access to that data).