What you’ll learn
Who this course is for:
Can I download Microservicios con Spring Cloud y Angular full stack course?You can download videos for offline viewing in the Android/iOS app. When course instructors enable the downloading feature for lectures of the course, then it can be downloaded for offline viewing on a desktop.Can I get a certificate after completing the course?Yes, upon successful completion of the course, learners will get the course e-Certification from the course provider. The Microservicios con Spring Cloud y Angular full stack course certification is a proof that you completed and passed the course. You can download it, attach it to your resume, share it through social media.Are there any other coupons available for this course?You can check out for more Udemy coupons @ www.coursecouponclub.comNote: 100% OFF Udemy coupon codes are valid for maximum 3 days only. Look for "ENROLL NOW"
button at the end of the post. A Secure Single Page ApplicationIn this tutorial we show some nice features of Spring Security, Spring Boot and Angular working together to provide a pleasant and secure user experience. It should be accessible to beginners with Spring and Angular, but there also is plenty of detail that will be of use to experts in either. This is actually the first in a series of sections on Spring Security and Angular, with new features exposed in each one successively. We’ll improve on the application in the second and subsequent installments, but the main changes after this are architectural rather than functional. Spring and the Single Page ApplicationHTML5, rich browser-based features, and the "single page application" are extremely valuable tools for modern developers, but any meaningful interactions will involve a backend server, so as well as static content (HTML, CSS and JavaScript) we are going to need a backend server. The backend server can play any or all of a number of roles: serving static content, sometimes (but not so often these days) rendering dynamic HTML, authenticating users, securing access to protected resources, and (last but not least) interacting with JavaScript in the browser through HTTP and JSON (sometimes referred to as a REST API). Spring has always been a popular technology for building the backend features (especially in the enterprise), and with the advent of Spring Boot things have never been easier. Let’s have a look at how to build a new single page application from nothing using Spring Boot, Angular and Twitter Bootstrap. There’s no particular reason to choose that specific stack, but it is quite popular, especially with the core Spring constituency in enterprise Java shops, so it’s a worthwhile starting point. Create a New ProjectWe are going to step through creating this application in some detail, so that anyone who isn’t completely au fait with Spring and Angular can follow what is happening. If you prefer to cut to the chase, you can skip to the end where the application is working, and see how it all fits together. There are various options for creating a new project:
The source code for the complete project we are going to build is in Github here, so you can just clone the project and work directly from there if you want. Then jump to the next section. Using CurlThe easiest way to create a new project to get started is via the Spring Boot Initializr. E.g. using curl on a UN*X like system:
You can then import that project (it’s a normal Maven Java project by default) into your favourite IDE, or just work with the files and "mvn" on the command line. Then jump to the next section. Using Spring Boot CLIYou can create the same project using the Spring Boot CLI, like this:
Using the Initializr WebsiteIf you prefer you can also get the same code directly as a .zip file from the Spring Boot Initializr. Just open it up in your browser and select dependencies "Web" and "Security", then click on "Generate Project". The .zip file contains a standard Maven or Gradle project in the root directory, so you might want to create an empty directory before you unpack it. Then jump to the next section.
Using Spring Tool SuiteIn Spring Tool Suite (a set of Eclipse plugins) you can also create and import a project using a wizard at Add an Angular AppThe core of a single page application in Angular (or any modern front-end framework) these days is going to be a Node.js build. Angular has some tools for setting this up quickly, so lets use those, and also keep the option of building with Maven, like any other Spring Boot application. The details of how to set up the Angular app are covered elsewhere, or you can just checkout the code for this tutorial from github. Running the ApplicationOnce the Angular app is primed, your application will be loadable in a browser (even though it doesn’t do much yet). On the command line you can do this and go to a browser at http://localhost:8080. When you load the home page you should get a browser dialog asking for username and password (the username is "user" and the password is printed in the console logs on
startup). There’s actually no content yet (or maybe the default "hero" tutorial content from the
In an IDE, just run the To package and run as a standalone JAR, you can do this:
Customize the Angular ApplicationLet’s customize the "app-root" component (in "src/app/app.component.ts"). A minimal Angular application looks like this: app.component.ts
Most of the code in this TypeScript is boiler plate. The interesting stuff is all going to be in the app.component.html
If you added those files under "src/app" and rebuilt your app it should now
be secure and functional, and it will say "Hello World!". The Adding Dynamic ContentSo far we have an application with a greeting that is hard coded. That’s useful for learning how things fit together, but really we expect content to come from a backend server, so let’s create an HTTP endpoint that we can use to grab a greeting. In your
application class (in "src/main/java/demo"), add the UiApplication.java
Run that application and try to curl the "/resource" endpoint and you will find that it is secure by default:
Loading a Dynamic Resource from AngularSo let’s grab that message in the browser. Modify the app.component.ts
We injected an
To enable the dependency injection of the app.module.ts
Run the application again (or just reload the home page in the browser), and you will see the dynamic message with its unique ID. So, even though the resource is protected and you can’t curl it directly, the browser was able to access the content. We have a secure single page application in less than a hundred lines of code!
How Does it Work?The interactions between the browser and the backend can be seen in your browser if you use some developer tools (usually F12 opens this up, works in Chrome by default, may require a plugin in Firefox). Here’s a summary:
You might not see the 401 because the browser treats the home page load as a single interaction, and you might see 2 requests for "/resource" because there is a CORS negotiation. Look more closely at the requests and you will see that all of them have an "Authorization" header, something like this:
The browser is sending the username and password with every request (so remember to use HTTPS exclusively in production). There’s nothing "Angular" about that, so it works with your JavaScript framework or non-framework of choice. What’s Wrong with That?On the face of it, it seems like we did a pretty good job, it’s concise, easy to implement, all our data are secured by a secret password, and it would still work if we changed the front end or backend technologies. But there are some issues.
CSRF isn’t really an issue with our application as it stands since it only needs to GET the backend resources (i.e. no state is changed in the server). As soon as you have a POST, PUT or DELETE in your application it simply isn’t secure any more by any reasonable modern measure. In the next section in this series we will extend the application to use form-based authentication, which is a lot more flexible than HTTP Basic. Once we have a form we will need CSRF protection, and both
Spring Security and Angular have some nice out-of-the box features to help with this. Spoiler: we are going to need to use the The Login PageIn this section we continue our discussion of how to use Spring Security with Angular in a "single page application". Here we show how to use Angular to authenticate a user via a form and fetch a secure resource to render in the UI. This is the second in a series of sections, and you can catch up on the basic building blocks of the application or build it from scratch by reading the first section, or you can just go straight to the source code in Github. In the first section we built a simple application that used HTTP Basic authentication to protect the backend resources. In this one we add a login form, give the user some control over whether to authenticate or not, and fix the issues with the first iteration (principally lack of CSRF protection).
Add Navigation to the Home PageThe core of an Angular application is an HTML template for the basic page layout. We already had a really basic one, but for this application we need to offer some navigation features (login, logout, home), so let’s modify it (in app.component.html
The main content is a The app.module.ts
We added a dependency on an Angular module called "RouterModule" and this allowed us to inject a magic We also sneaked the The UI components are all "declarations" and the service glue is a "provider". The app.component.ts
Salient features:
The app.service.ts
The The GreetingThe greeting content from the old home page can go right next to the "app.component.html" in "src/app": home.component.html
Since the user now has the choice whether to login or not (before it was all controlled by the browser), we need to distinguish in the UI between content that is secure and that which is not. We have anticipated this by adding references to an (as yet non-existent) The
home.component.ts
The Login FormThe login form also gets its own component: login.component.html
This is a very standard login form, with 2 inputs for username and password and a button for submitting the form via an Angular event handler The Authentication ProcessTo support the login form we just added we need to add some more features. On the client side these will be implemented in the Submitting the Login FormTo submit the form we need to define the login.component.ts
In addition to initializing the The The Currently Authenticated UserTo service the UiApplication.java
This is a useful trick in a Spring Security application. If the "/user" resource is reachable
then it will return the currently authenticated user (an Handling the Login Request on the ServerSpring Security makes it easy to handle the login request. We just need to add some configuration to our main application class (e.g. as an inner class): UiApplication.java
This is a standard Spring Boot application with Spring Security customization, just allowing anonymous access to the static (HTML) resources. The HTML resources need to be available to anonymous users, not just ignored by Spring Security, for reasons that will become clear. The last thing we need to remember is to make the JavaScript components provided by Angular available anonymously to the application. We could do that in the application.yml
If you run the app at this point you will find that the browser pops up a Basic authentication dialogue (for user and password). It does this
because it sees a 401 reponse from the XHR requests to First extend the default app.module.ts
The syntax here is boilerplate. The To install this new app.module.ts
LogoutThe application is almost finished functionally. The last thing we need to do is implement the logout feature that we sketched in the home page. If the user is authenticated then we show a "logout" link and hook it to a CSRF ProtectionThe application is almost ready to use, and in fact if you run it you will find that everything we built so far actually works except the logout link. Try using it and look at the responses in the browser and you will see why:
That’s good because it means that Spring Security’s built-in CSRF protection has kicked in to prevent us from shooting ourselves in the foot. All it wants is a token sent to it in a header called "X-CSRF". The value of the CSRF token was available server side in the So on the server we need a custom filter that will send the cookie. Angular wants the cookie name to be "XSRF-TOKEN" and Spring Security provides it as a request attribute by default, so
we just need to transfer the value from a request attribute to a cookie. Fortunately, Spring Security (since 4.1.0) provides a special UiApplication.java
With those changes in place we don’t need to do anything on the client side and the login form is now working. How Does it Work?The interactions between the browser and the backend can be seen in your browser if you use some developer tools (usually F12 opens this up, works in Chrome by default, may require a plugin in Firefox). Here’s a summary:
The responses that are marked "ignored" above are HTML responses received by Angular in an XHR call, and since we aren’t processing that data the HTML is dropped on the floor. We do look for an authenticated user in the case of the "/user" resource, but since it isn’t there in the first call, that response is dropped. Look more closely at the requests and you will see that they all have cookies. If you start with a clean browser (e.g. incognito in Chrome), the
very first request has no cookies going off to the server, but the server sends back "Set-Cookie" for "JSESSIONID" (the regular
Help, How is My Application Going to Scale?"But wait…" you are saying, "isn’t it Really Bad to use session state in a single-page application?" The answer to that question is going to have to be "mostly", because it very definitely is a Good Thing to use the session for authentication and CSRF protection. That state has to be stored somewhere, and if you take it out of the session, you are going to have to put it somewhere else and manage it manually yourself, on both the server and the client. That’s just more code and probably more maintenance, and generally re-inventing a perfectly good wheel. "But, but…" you are going to respond, "how do I scale my application horizontally now?" This is the "real" question you were asking above, but it tends to get shortened to "session state is bad, I must be stateless". Don’t panic. The main point to take on board here is that security is stateful. You can’t have a secure, stateless application. So where are you going to store the state? That’s all there is to it. Rob Winch gave a very useful and insightful talk at Spring Exchange 2014 explaining the need for state (and the ubiquity of it - TCP and SSL are stateful, so your system is stateful whether you knew it or not), which is probably worth a look if you want to look into this topic in more depth. The good news is you have a choice. The easiest choice is to store the session data in-memory, and rely on sticky sessions in your load balancer to route requests from the same session back to the same JVM (they all support that somehow). That’s good enough to get you off the ground and will work for a really large number of use cases. The other choice is to share the session data between instances of your application. As long as you are strict and only store the security data, it is small and changes infrequently (only when users log in and out, or their session times out), so there shouldn’t be any major infrastructure problems. It’s also really easy to do with Spring Session. We’ll be using Spring Session in the next section in this series, so there’s no need to go into any detail about how to set it up here, but it is literally a few lines of code and a Redis server, which is super fast.
But, What about My Custom Token Implementation (it’s Stateless, Look)?If that was your response to the last section, then read it again because maybe you didn’t get it the first time. It’s probably not stateless if you stored the token somewhere, but even if you didn’t (e.g. you use JWT encoded tokens), how are you going to provide CSRF protection? It’s important. Here’s
a rule of thumb (attributed to Rob Winch): if your application or API is going to be accessed by a browser, you need CSRF protection. It’s not that you can’t do it without sessions, it’s just that you’d have to write all that code yourself, and what would be the point because it’s already implemented and works perfectly well on top of ConclusionThe
application we have now is close to what a user might expect in a "real" application in a live environment, and it probably could be used as a template for building out into a more feature rich application with that architecture (single server with static content and JSON resources). We are using the The Resource ServerIn this section we continue our discussion of how to use Spring Security with Angular in a "single page application". Here we start by breaking out the "greeting" resource that we are using as the dynamic content in our application into a separate server, first as an unprotected resource, and then protected by an opaque token. This is the third in a series of sections, and you can catch up on the basic building blocks of the application or build it from scratch by reading the first section, or you can just go straight to the source code in Github, which is in two parts: one where the resource is unprotected, and one where it is protected by a token.
A Separate Resource ServerClient Side ChangesOn the client side there isn’t very much to do to move the resource to a different backend. Here’s the "home" component in the last section: home.component.ts
All we need to do to this is change the URL. For example, if we are going to run the new resource on localhost, it could look like this: home.component.ts
Server Side ChangesThe UI server is trivial to change: we just need to remove the
You can then import that project (it’s a normal Maven Java project by default) into your favourite IDE, or just work with the files and "mvn" on the command line. ResourceApplication.java
Once that is done your application will be loadable in a browser. On the command line you can do this
and go to a browser at http://localhost:9000 and you should see JSON with a greeting. You can bake in the port change in If you try loading that resource from the UI (on port 8080) in a browser, you will find that it doesn’t work because the browser won’t allow the XHR request. CORS NegotiationThe browser tries to negotiate with our resource server to find out if it is allowed to access it according to the Cross Origin Resource Sharing protocol. It’s not an Angular responsibility, so just like the cookie contract it will work like this with all JavaScript in the browser. The two servers do not declare that they have a common origin, so the browser declines to send the request and the UI is broken. To fix that we need to support the CORS protocol which involves a "pre-flight" OPTIONS request and some headers to list the allowed behaviour of the caller. Spring 4.2 has some nice fine-grained CORS support, so we can just add an annotation to our controller mapping, for example: ResourceApplication.java
Securing the Resource ServerGreat! We have a working application with a new architecture. The only problem is that the resource server has no security. Adding Spring SecurityWe can also look at how to add security to the resource server as a filter layer, like in the UI server. The first step is really easy: just add Spring Security to the classpath in the Maven POM: pom.xml
Re-launch the resource server and, hey presto! It’s secure:
We are getting a redirect to a (whitelabel) login page because curl is not sending the same headers that our Angular client will. Modifying the command to send more similar headers:
So all we need to do is teach the client to send credentials with every request. Token AuthenticationThe internet, and people’s Spring backend projects, are littered with custom token-based authentication solutions. Spring Security provides a barebones Remember from Part II of this
series that Spring Security uses the Spring SessionThat part of the solution is pretty easy with Spring Session. All we need is a shared data store (Redis
and JDBC are supported out of the box), and a few lines of configuration in the servers to set up a In the UI application we need to add some dependencies to our POM: pom.xml
Spring Boot and Spring Session work together to connect to Redis and store session data centrally. With that 1 line of code in place and a Redis server running on localhost you can run the UI application, login with some valid user credentials, and the session data (the authentication) will be stored in redis.
Sending a Custom Token from the UIThe only missing piece is the transport mechanism for the key to the data in the store. The key is the home.component.ts
(A more elegant solution might be to grab the token as needed, and use our Instead of going directly to "http://localhost:9000" we have wrapped that call in the success callback of a call to a new custom endpoint on the UI server at "/token". The implementation of that is trivial: UiApplication.java
So the UI application is ready and will include the session ID in a header called "X-Auth-Token" for all calls to the backend. Authentication in the Resource ServerThere is one tiny change to the resource server for it to be able to accept the custom header. The CORS configuration has to nominate that header as an allowed one from remote clients, e.g. ResourceApplication.java
The pre-flight check from the browser will now be handled by Spring MVC, but we need to tell Spring Security that it is allowed to let it through: ResourceApplication.java
All that remains is to pick up the custom token in the resource server and use it to authenticate our user. This turns out to be pretty straightforward because all we need to do is tell Spring Security where the session repository is, and where to look for the token (session ID) in an incoming request. First we need to add the Spring Session and Redis dependencies, and then we can set up the ResourceApplication.java
This There is one final change to the resource server to make it work with our new authentication scheme. Spring Boot default security is stateless, and we want this to store authentication in the session, so we need to be explicit in application.yml
This says to Spring Security "never create a session, but use one if it is there" (it will already be there because of the authentication in the UI). Re-launch the resource server and open the UI up in a new browser window. Why Doesn’t it All Work With Cookies?We had to use a custom header and write code in the client to populate the header, which isn’t terribly complicated, but it seems to contradict the advice in Part II to use cookies and sessions wherever possible. The argument there was that not to do so introduces additional unecessary complexity, and for sure the implementation we have now is the most complex we have seen so far: the technical part of the solution far outweighs the business logic (which is admittedly tiny). This is definitely a fair criticism (and one we plan to address in the next section in this series), but let’s just briefly look at why it’s not as simple as just using cookies and sessions for everything. At least we are still using the session, which makes sense because Spring Security and the Servlet container know how to do that with no effort on our part. But couldn’t we have continued to use cookies to transport the authentication token? It would have been nice, but there is a reason it wouldn’t work, and that is that the browser wouldn’t let us. You can just go poking around in the browser’s cookie store from a JavaScript client, but there are some restrictions, and for good reason. In particular you don’t have access to the cookies that were sent by the server as "HttpOnly" (which you will see is the case by default for session cookies). You also can’t set cookies in outgoing requests, so we couldn’t set a "SESSION" cookie (which is the Spring Session default cookie name), we had to use a custom "X-Session" header. Both these restrictions are for your own protection so malicious scripts cannot access your resources without proper authorization. TL;DR the UI and resource servers do not have a common origin, so they cannot share cookies (even though we can use Spring Session to force them to share sessions). ConclusionWe have duplicated the features of the application in Part II of this series: a home page with a greeting fetched from a remote backend, with login and logout links in a navigation bar. The difference is that the greeting comes from a resource server that is a standalone, instead of being embedded in the UI server. This added significant complexity to the implementation, but the good news is that we have a mostly configuration-based (and practically 100% declarative) solution. We could even make the solution 100% declarative by extracting all the new code into libraries (Spring configuration and Angular custom directives). We are going to defer that interesting task for after the next couple of installments. In the next section we are going to look at a different really great way to reduce all the complexity in the current implementation: the API Gateway Pattern (the client sends all its requests to one place and authentication is handled there).
The API GatewayIn this section we continue our discussion of how to use Spring Security with Angular in a "single page application". Here we show how to build an API Gateway to control the authentication and access to the backend resources using Spring Cloud. This is the fourth in a series of sections, and you can catch up on the basic building blocks of the application or build it from scratch by reading the first section, or you can just go straight to the source code in Github. In the last section we built a simple distributed application that used Spring Session to authenticate the backend resources. In this one we make the UI server into a reverse proxy to the backend resource server, fixing the issues with the last implementation (technical complexity introduced by custom token authentication), and giving us a lot of new options for controlling access from the browser client.
Creating an API GatewayAn API Gateway is a single point of entry (and control) for front end clients, which could be browser based (like the examples in this section) or mobile. The client only has to know the URL of one server, and the backend can be refactored at will with no change, which is a significant advantage. There are other advantages in terms of centralization and control: rate limiting, authentication, auditing and logging. And implementing a simple reverse proxy is really simple with Spring Cloud. If you were following along in the code, you will know that the application implementation at the end of the last section was a bit complicated, so it’s not a great place to iterate away from. There was, however, a halfway point which we could start from more easily, where the backend resource wasn’t yet secured with Spring Security. The source code for this is a separate project in Github so we are going to start from there. It has a UI server and a resource server and they are talking to each other. The resource server doesn’t have Spring Security yet so we can get the system working first and then add that layer.
Declarative Reverse Proxy in One LineTo turn it into an API Gateway, the UI server needs one small tweak. Somewhere in the Spring configuration we need to add an UiApplication.java
and in an external configuration file we need to map a local resource in the UI server to a remote one in the external configuration ("application.yml"): application.yml
This says "map paths with the pattern /resource/** in this server to the same paths in the remote server at localhost:9000". Simple and yet effective (OK so it’s 6 lines including the YAML, but you don’t always need that)! All we need to make this work is the right stuff on the classpath. For that purpose we have a few new lines in our Maven POM: pom.xml
Note the use of the "spring-cloud-starter-zuul" - it’s a starter POM just like the Spring Boot ones, but it governs the dependencies we need for this Zuul proxy. We are also using Consuming the Proxy in the ClientWith those changes in place our application still works, but we haven’t actually used the new proxy yet until we modify the client. Fortunately that’s trivial. We just need to revert the change we made going from the "single" to the "vanilla" samples in the last section: home.component.ts
Now when we fire up the servers everything is working and the requests are being proxied through the UI (API Gateway) to the resource server. Further SimplificationsEven better: we don’t need the CORS filter any more in the resource server. We threw that one together pretty quickly anyway, and it should have been a red light that we had to do anything as technically focused by hand (especially where it concerns security). Fortunately it is now redundant, so we can just throw it away, and go back to sleeping at night! Securing the Resource ServerYou might remember in the intermediate state that we started from there is no security in place for the resource server.
application.properties
Suppose that we decide we do need security at the software level (quite likely for a number of reasons). That’s not going to be a problem, because all we need to do is add Spring Security as a dependency (in the resource server POM): pom.xml
That’s enough to get us a secure resource server, but it won’t get us a working application yet, for the same reason that it didn’t in Part III: there is no shared authentication state between the two servers. Sharing Authentication StateWe can use the same mechanism to share authentication (and CSRF) state as we did in the last, i.e. Spring Session. We add the dependency to both servers as before: pom.xml
but this time the configuration is much
simpler because we can just add the same application.yml
Then we can move on to the resource server. There are two small changes to make: one is to explicitly disable HTTP Basic in the resource server (to prevent the browser from popping up authentication dialogs): ResourceApplication.java
and the other is to explicitly ask for a non-stateless session creation policy in As long as redis is still running in the background (use the How Does it Work?What is going on behind the scenes now? First we can look at the HTTP requests in the UI server (and API Gateway):
That’s identical to the sequence at the end of Part II except for the fact that the cookie names are slightly different ("SESSION" instead of "JSESSIONID") because we are using Spring Session. But the architecture is different and that last request to "/resource" is special because it was proxied to the resource server. We can see the reverse proxy in action by looking at the "/trace" endpoint in the UI server (from Spring Boot Actuator, which we added with the Spring Cloud dependencies). Go to http://localhost:8080/trace in a new browser (if you don’t have one already get a JSON plugin for your browser to make it nice and readable). You will need to authenticate with HTTP Basic (browser popup), but the same credentials are valid as for your login form. At or near the start you should see a pair of requests something like this:
/trace
The second entry there is the request from the client to the gateway on "/resource" and you can see the cookies (added by the browser) and the CSRF header (added by Angular as discussed in Part II). The first entry has ConclusionWe covered quite a lot in this section but we got to a really nice place where there is a minimal amount of boilerplate code in our two servers, they are both nicely secure and the user experience isn’t compromised. That alone would be a reason to use the API Gateway pattern, but really we have only scratched the surface of what that might be used for (Netflix uses it for a lot of things). Read up on Spring Cloud to find out more on how to make it easy to add more features to the gateway. The next section in this series will extend the application architecture a bit by extracting the authentication responsibilities to a separate server (the Single Sign On pattern). Single Sign On with OAuth2In this section we continue our discussion of how to use Spring Security with Angular in a "single page application". Here we show how to use Spring Security OAuth together with Spring Cloud to extend our API Gateway to do Single Sign On and OAuth2 token authentication to backend resources. This is the fifth in a series of sections, and you can catch up on the basic building blocks of the application or build it from scratch by reading the first section, or you can just go straight to the source code in Github. In the last section we built a small distributed application that used Spring Session to authenticate the backend resources and Spring Cloud to implement an embedded API Gateway in the UI server. In this section we extract the authentication responsibilities to a separate server to make our UI server the first of potentially many Single Sign On applications to the authorization server. This is a common pattern in many applications these days, both in the enterprise and in social startups. We will use an OAuth2 server as the authenticator, so that we can also use it to grant tokens for the backend resource server. Spring Cloud will automatically relay the access token to our backend, and enable us to further simplify the implementation of both the UI and resource servers.
Our first step is to create a new server to handle authentication and token management. Following the steps in Part I we can begin with Spring Boot Initializr. E.g. using curl on a UN*X like system:
You can then import that project (it’s a normal Maven Java project by default) into your favourite IDE, or just work with the files and "mvn" on the command line.
Adding the OAuth2 DependenciesWe need to add the Spring OAuth dependencies, so in our POM we add: pom.xml
The authorization server is pretty easy to implement. A minimal version looks like this: AuthserverApplication.java
We only have to do 1 more thing (after adding application.properties
This registers a client "acme" with a secret and some authorized grant types including "authorization_code". Now let’s get it running on port 9999, with a predictable password for testing: application.properties
We also set the context path so that it doesn’t use the default ("/") because otherwise you can get cookies for other servers on localhost being sent to the wrong server. So get the server running and we can make sure it is working: or start the Testing the Authorization Server
The code can be exchanged for an access token using the "acme" client credentials on the token endpoint:
The access token is a UUID ("2219199c…"), backed by an in-memory token store in the server. We also got a refresh token that we can use to get a new access token when the current one expires.
If you followed the link above you would have seen the whitelabel UI provided by Spring OAuth. To start with we will use this and we can come back later to beef it up like we did in Part II for the self-contained server. Changing the Resource ServerIf we follow on from Part IV, our resource server is using Spring Session for authentication, so we can take that out and replace it with Spring OAuth. We also need to remove the Spring Session and Redis dependencies, so replace this: pom.xml
with this: pom.xml
and then remove the session ResourceApplication.java
With that one change the app is ready to challenge for an access token instead of HTTP Basic, but we need a config change to actually finish the process. We are going to add a small amount of external configuration (in "application.properties") to allow the resource server to decode the tokens it is given and authenticate a user: application.properties
This tells the server that it can use the token to access a "/user" endpoint and use that to derive
authentication information (it’s a bit like the "/me" endpoint in the Facebook API). Effectively it provides a way for the resource server to decode the token, as expressed by the Run the application and hit the home page with a command line client:
and you will see a 401 with a "WWW-Authenticate" header indicating that it wants a bearer token.
Implementing the User EndpointOn the authorization server we can easily add that endpoint AuthserverApplication.java
We added a With that endpoint in place we can test it and the greeting resource, since they both now accept bearer tokens that were created by the authorization server:
(substitute the value of the access token that you obtain from your own authorization server to get that working yourself). The UI ServerThe final piece of
this application we need to complete is the UI server, extracting the authentication part and delegating to the authorization server. So, as with the resource server, we first need to remove the Spring Session and Redis dependencies and replace them with Spring OAuth2. Because we are using Zuul in the UI layer we actually use Once that is done we can remove the session filter and the "/user" endpoint as well, and set up the application to redirect to the authorization server (using the UiApplication.java
Recall from Part
IV that the UI server, by virtue of the application.yml
Lastly, we need to change the application to a SecurityConfiguration.java
The main changes (apart
from the base class name) are that the matchers go into their own method, and there is no need for There are also some mandatory external configuration properties for the application.yml
The bulk of that is about the OAuth2 client ("acme") and the authorization server locations. There is also a
In the ClientThere are some tweaks to the UI application on the front end that we still need to make to trigger the redirect to the authorization server. In this simple demo we can strip the Angular app down to its bare essentials so you can see what is going on more clearly. So we forgo, for now, the use of forms or routes, and we go back to a single Angular component: app.component.ts
The Now we need to create the template for this new component: app.component.html
and include it in the home page as Note that the navigation link for "Login" is a regular link with an How Does it Work?Run all the servers together now, and visit the UI in a browser at http://localhost:8080. Click on the "login" link and you will be redirected to the authorization server to authenticate (HTTP Basic popup) and approve the token grant (whitelabel HTML), before being redirected to the home page in the UI with the greeting fetched from the OAuth2 resource server using the same token as we authenticated the UI with. The interactions between the browser and the backend can be seen in your browser if you use some developer tools (usually F12 opens this up, works in Chrome by default, may require a plugin in Firefox). Here’s a summary:
The requests prefixed with (uaa) are to the authorization server. The responses that are marked "ignored" are responses received by Angular in an XHR call, and since we aren’t processing that data they are dropped on the floor. We do look for an authenticated user in the case of the "/user" resource, but since it isn’t there in the first call, that response is dropped. In the "/trace" endpoint of the UI (scroll down to the bottom) you will see the proxied
backend requests to "/user" and "/resource", with
The Logout ExperienceIf you click on the "logout" link you will see that the home page changes (the greeting is no longer displayed) so the user is no longer authenticated with the UI server. Click back on "login" though and you actually don’t need to go back through the authentication and approval cycle in the authorization server (because you haven’t logged out of that). Opinions will be divided as to whether that is a desirable user experience, and it’s a notoriously tricky problem (Single Sign Out: Science Direct article and Shibboleth docs). The ideal user experience might not be technically feasible, and you also have to be suspicious sometimes that users really want what they say they want. "I want 'logout' to log me out" sounds simple enough, but the obvious response is, "Logged out of what? Do you want to be logged out of all the systems controlled by this SSO server, or just the one that you clicked the 'logout' link in?" If you are interested then there is a later section of this tutorial where it is discussed in more depth. ConclusionThis is almost the end of our shallow tour through the Spring Security and Angular stack. We have a nice architecture now with clear responsibilities in three separate components, UI/API Gateway, resource server and authorization server/token granter. The amount of non-business code in all layers is now minimal, and it’s easy to see where to extend and improve the implementation with more business logic. The next steps will be to tidy up the UI in our authorization server, and probably add some more tests, including tests on the JavaScript client. Another interesting task is to extract all the boiler plate code and put it in a library (e.g. "spring-security-angular") containing Spring Security and Spring Session autoconfiguration and some webjars resources for the navigation controller in the Angular piece. Having read the sections in thir series, anyone who was hoping to learn the inner workings of either Angular or Spring Security will probably be disappointed, but if you wanted to see how they can work well together and how a little bit of configuration can go a long way, then hopefully you will have had a good experience. Spring Cloud is new and these samples required snapshots when they were written, but there are release candidates available and a GA release coming soon, so check it out and send some feedback via Github or gitter.im. The next section in the series is about access decisions (beyond authentication) and employs multiple UI applications behind the same proxy. Addendum: Bootstrap UI and JWT Tokens for the Authorization ServerYou will find another version of this application in the source code in Github which has a pretty login page and user approval page implemented similarly to the way we did the login page in Part II. It also uses JWT to encode the tokens, so instead of using the "/user" endpoint, the resource server can pull enough information out of the token itself to do a simple authentication. The browser client still uses it, proxied through the UI server, so that it can determine if a user is authenticated (it doesn’t need to do that very often, compared to the likely number of calls to a resource server in a real application). Multiple UI Applications and a GatewayIn this section we continue our discussion of how to use Spring Security with Angular in a "single page application". Here we show how to use Spring Session together with Spring Cloud to combine the features of the systems we built in parts II and IV, and actually end up building 3 single page applications with quite different responsibilities. The aim is to build a Gateway (like in part IV) that is used not only for API resources but also to load the UI from a backend server. We simplify the token-wrangling bits of part II by using the Gateway to pass through the authentication to the backends. Then we extend the system to show how we can make local, granular access decisions in the backends, while still controlling identity and authentication at the Gateway. This is a very powerful model for building distributed systems in general, and has a number of benefits that we can explore as we introduce the features in the code we build.
Target ArchitectureHere’s a picture of the basic system we are going to build to start with: Like the other sample applications in this series it has a UI (HTML and JavaScript) and a Resource server. Like the sample in Section IV it has a Gateway, but here it is separate, not part of the UI. The UI effectively becomes part of the backend, giving us even more choice to re-configure and re-implement features, and also bringing other benefits as we will see. The browser goes to the Gateway for everything and it doesn’t have to know about the architecture of the backend (fundamentally, it has no idea that there is a back end). One of the things the browser does in this Gateway is authentication, e.g. it sends a username and password like in Section II, and it gets a cookie in return. On subsequent requests it presents the cookie automatically and the Gateway passes it through to the backends. No code needs to be written on the client to enable the cookie passing. The backends use the cookie to authenticate and because all components share a session they share the same information about the user. Contrast this with Section V where the cookie had to be converted to an access token in the Gateway, and the access token then had to be independently decoded by all the backend components. As in Section IV the Gateway simplifies the interaction between clients and servers, and it presents a small, well-defined surface on which to deal with security. For example, we don’t need to worry about Cross Origin Resource Sharing, which is a welcome relief since it is easy to get wrong. The source code for the complete project we are going to build is in Github here, so you can just clone the project and work directly from there if you want. There is an extra component in the end state of this system ("double-admin") so ignore that for now. Building the BackendIn this architecture the backend is very similar to the "spring-session" sample we built in Section III, with the exception that it doesn’t actually need a login page. The easiest way to get to what we want here is probably to copy the "resource" server from Section III and take the UI from the "basic" sample in Section I. To get from the "basic" UI to the one we want here, we need only to add a couple of dependencies (like when we first used Spring Session in Section III): pom.xml
Since this is now a UI there is no need for the "/resource" endpoint. When you have done that you will have a very simple Angular application (the same as in the "basic" sample), which simplifies testing and reasoning about its behaviour greatly. Lastly, we want this server to run as a backend, so we’ll give it a non-default port to listen on (in application.properties
If that’s the whole content The Resource ServerThe Resource server is easy to generate from one of our existing samples. It is the same as the "spring-session" Resource server in
Section III: just a "/resource" endpoint Spring Session to get the distributed session data. We want this server to have a non-default port to listen on, and we want to be able to look up authentication in the session so we need this (in application.properties
We are going to be POSTing changes to our message resource, which is a new feature in this tutorial. It means that we are going to need CSRF protection in the backend, and we need to do the usual trick to make Spring Security play nicely with Angular:
The completed sample is here in github if you want to take a peek. The GatewayFor
an initial implementation of a Gateway (the simplest thing that could possibly work) we can just take an empty Spring Boot web application and add the
You can then import that project (it’s a normal Maven Java project by default) into your favourite IDE, or just work with the files and "mvn" on the command line. There is a version in github if you want to go from there, but it has a few extra features that we don’t need yet. Starting from the blank Initializr application, we add the Spring Session dependency (like in the UI above). The Gateway is ready to run, but it doesn’t yet know about our backend services, so let’s just set that up in its application.yml
There are 2 routes in the proxy, both of which pass cookies downstream using the Up and RunningWe now have three components, running on 3 ports. If you point the browser at http://localhost:8080/ui/ you should get an HTTP Basic challenge, and you can authenticate as "user/password" (your credentials in the Gateway), and once you do that you should see a greeting in the UI, via a backend call through the proxy to the Resource server. The interactions between the browser and the backend can be seen in your browser if you use some developer tools (usually F12 opens this up, works in Chrome by default, may require a plugin in Firefox). Here’s a summary:
You might not see the 401 because the browser treats the home page load as a single interaction. All requests are proxied (there is no content in the Gateway yet, beyond the Actuator endpoints for management). Hurrah, it works! You have two backend servers, one of which is a UI, each with independent capabilities and able to be tested in isolation, and they are connected together with a secure Gateway that you control and for which you have configured the authentication. If the backends are not accessible to the browser it doesn’t matter (in fact it’s probably an advantage because it gives you yet more control over physical security). Adding a Login FormJust as in the "basic" sample in Section I we can now add a login form to the Gateway, e.g.
by copying the code from Section II. When we do that we can also add some basic navigation elements in the Gateway, so the user doesn’t have to know the path to the UI backend in the proxy. So let’s first copy the static assets from the "single" UI into the Gateway, delete the message rendering and insert a login form into our home page (in the
app.html
Instead of the message rendering we will have a nice big navigation button: index.html
If you are looking at the sample in github, it also has a minimal navigation bar with a "Logout" button. Here’s the login form in a screenshot: To support the login form we need some TypeScript with a component implementing the app.component.ts
where the
implementation of the We can use the If we run this enhanced Gateway, instead of having to remember the URL for the UI we can just load the home page and follow links. Here’s the home page for an authenticated user: Granular Access Decisions in the BackendUp to now our application is functionally very similar to the one in Section III or Section IV, but with an additional dedicated Gateway. The advantage of the extra layer may not be yet apparent, but we can emphasise it by expanding the system a bit. Suppose we want to use that Gateway to expose another backend UI, for users to "administrate" the content in the main UI, and that we want to restrict access to this feature to users with special roles. So we will add an "Admin" application behind the proxy, and the system will look like this: There is a new
component (Admin) and a new route in the Gateway in application.yml
The fact that the existing UI is available to users in the "USER" role is indicated on the block diagram above in the Gateway box (green lettering), as is the fact that the "ADMIN" role is needed to go to the Admin application. The access decision for the "ADMIN" role could be applied in the Gateway, in which case it would appear in a So first, create a new Spring Boot application, or copy the UI and edit it. You won’t need to change much in the UI app except the name to start with. The finished app is in Github here. Suppose that within the Admin application we want to distinguish between "READER" and "WRITER" roles, so that we can permit (let’s say) users who are auditors to view the changes made by the main admin users. This is a granular access decision, where the rule is only known, and should only be known, in the backend application. In the Gateway we only need to ensure that our user accounts have the roles needed, and this information is available, but the Gateway doesn’t need to know how to interpret it. In the Gateway we create user accounts to keep the sample application self-contained: SecurityConfiguration.class
where the "admin" user has been enhanced with 3 new roles ("ADMIN", "READER" and "WRITER") and we have also added an "audit" user with "ADMIN" access, but not "WRITER".
The access decisions go in the Admin application. For the "ADMIN" role (which is required globally for this backend) we do it in Spring Security: SecurityConfiguration.java
For the "READER" and "WRITER" roles the application itself is split, and since the application is implemented in JavaScript, that is where we need to make the access decision. One way to do this is to have a home page with a computed view embedded in it via the router: app.component.html
The route is computed when the component loads: app.component.ts
the first thing the application does is look at check if the user is authenticated, and computes the route by looking at the user data. The routes are declared in the main module: app.module.ts
Each of those components (one for each route) has to be implemented
separately. Here’s the read.component.ts
read.component.html
The write.component.ts
write.component.html
The app.service.ts
To support this function on the backend we need the AdminApplication.java
Changes in the Gateway to Support Admin UIWe are going to use the roles to make access decisions in the Gateway as well (so we can conditionally display a link to the admin UI), so we should add the "roles" to the "/user" endpoint in the Gateway as well. Once that is in place we can add some JavaScript to set up a flag to indicate that the current user is an "ADMIN". In the app.component.ts
and we also need to reset the app.component.ts
and then in the HTML we can conditionally show a new link: app.component.html
Run all the apps and go to http://localhost:8080 to see the result. Everything should be working fine, and the UI should change depending on the currently authenticated user. Why are we Here?Now we have a nice little system with 2 independent user interfaces and a backend Resource server, all protected by the same authentication in a Gateway. The fact that the Gateway acts as a micro-proxy makes the implementation of the backend security concerns extremely simple, and they are free to concentrate on their own business concerns. The use of Spring Session has (again) avoided a huge amount of hassle and potential errors. A powerful feature is that the backends can independently have any kind of authentication they like (e.g. you can go directly to the UI if you know its physical address and a set of local credentials). The Gateway imposes a completely unrelated set of constraints, as long as it can authenticate users and assign metadata to them that satisfy the access rules in the backends. This is an excellent design for being able to independently develop and test the backend components. If we wanted to, we could go back to an external OAuth2 server (like in Section V, or even something completely different) for the authentication at the Gateway, and the backends would not need to be touched. A bonus feature of this architecture (single Gateway controlling authentication, and shared session token across all components) is that "Single Logout", a feature we identified as difficult to implement in Section V, comes for free. To be more precise, one particular approach to the user experience of single logout is automatically available in our finished system: if a user logs out of any of the UIs (Gateway, UI backend or Admin backend), he is logged out of all the others, assuming that each individual UI implemented a "logout" feature the same way (invalidating the session). Testing an Angular ApplicationIn this section we continue our discussion of how to use Spring Security with Angular in a "single page application". Here we show how to write and run unit tests for the client-side code using the Angular test framework. You can catch up on the basic building blocks of the application or build it from scratch by reading the first section, or you can just go straight to the source code in Github (the same source code as Part I, but with tests now added). This section actually has very little code using Spring or Spring Security, but it covers the client-side testing in a way that might not be so easy to find in the usual Angular community resources, and one which we feel will be comfortable for the majority of Spring users.
Writing a SpecificationOur "app" component in the "basic" application is very simple, so it won’t take a lot to test it thoroughly. Here’s a reminder of the code: app.component.ts
The main challenge we face is to provide the The Angular build in an app created from app.component.ts
In this very basic test suite we have these important elements:
The test function here is so trivial it actually only asserts that the component exists, so if that fails then the test will fail. Improving the Unit Test: Mocking HTTP BackendTo improve the spec to production grade we need to actually assert something about what happens when the controller loads. Since it makes a call to app.component.spec
The new pieces here are:
Running the SpecsTo run our test" code we can do End-to-End TestsAngular also has a standard build set up for "end-to-end tests" using a browser and your generated JavaScript. These are written as "specs" in the top-level ConclusionBeing able to run unit tests for Javascript is important in a modern web application and it’s a topic that we’ve ignored (or dodged) up to now in this series. With this installment we have presented the basic ingredients of how to write the tests, how to run them at development time and also, importantly, in a continuous integration setting. The approach we have taken is not going to suit everyone, so please don’t feel bad about doing it in a different way, but make sure you have all those ingredients. The way we did it here will probably feel comfortable to traditional Java enterprise developers, and integrates well with their existing tools and processes, so if you are in that category I hope you will find it useful as a starting point. More examples of testing with Angular and Jasmine can be found in plenty of places on the internet, but the first point of call might be the "single" sample from this series, which now has some up to date test code which is a bit less trivial than the code we needed to write for the "basic" sample in this tutorial. Logout from an OAuth2 Client ApplicationIn this section we continue our discussion of how to use Spring Security with Angular in a "single page application". Here we show how to take the OAuth2 samples and add a different logout experience. Many people who implement OAuth2 single sign on find that they have a puzzle to solve of how to logout "cleanly"? The reason it’s a puzzle is that there isn’t a single correct way to do it, and the solution you choose will be determined by the user experience you are looking for, and also the amount of complexity you are willing to take on. The reasons for the complexity stem from the fact that there are potentially multiple browser sessions in the system, all with different backend servers, so when a user logs out from one of them, what should happen to the others? This is the ninth section of a tutorial, and you can catch up on the basic building blocks of the application or build it from scratch by reading the first section, or you can just go straight to the source code in Github. Logout PatternsThe user experience with logout of the There are, broadly speaking, three patterns for logout from a UI app that is authenticated as an OAuth2 client:
Sometimes, even if you have an external authserver, you want to control the authentication and add an internal layer of access control (e.g. scopes or roles that the authserver doesn’t support). Then it’s a good idea to use the EA for authentication, but have an internal authserver that can add the additional details you need to the tokens. The Here are some options if you don’t want EA:
Note that where SL is hard or impossible, it might be better to put all the UIs behind a single gateway anyway. Then you can use GIA, which is easier, to control logout from your whole estate. The easiest two options, which apply nicely in the GIA pattern can be implemented in the tutorial sample as follows (take the Logout of Both Servers from BrowserIt’s quite easy to add a couple of lines of code to the browser client that logout from the authserver as soon as the UI app is logged out. E.g.
In this sample we hardcoded the authserver logout endpoint URL into the JavaScript, but it would be easy to externalize that if you needed to. It has to be a POST directly to the authserver because we want the session cookie to go along too. The XHR request will only go out from the browser with a cookie attached if we specifically ask for Conversely, on the server we need some CORS configuration because the request is coming from a different
domain. E.g. in the
The "/logout" endpoint has been given some special treatment. It is allowed to be called from any origin, and explicitly allows credentials (e.g. cookies) to be sent. The allowed headers are just the ones that Angular sends in teh sample app. In addition to the CORS configuration we also need to disable CSRF for the logout endpoint, because Angular will not send the
With those two simple changes, one in the UI app client, and one in the authserver, you will find that once you logout of the UI app, when you log back in, you will always be prompted for a password. Another useful change is to set the OAuth2 client to autoapprove, so that the user doesn’t have to approve the token grant. This is common in a internal authserver, where the user doesn’t perceive it as a separate system. In the
Invalidate Session in AuthserverIf you don’t like to give up the CSRF protection on the logout endpoint, you can try the other easy approach, which is to invalidate the user session in the authserver as soon as a token is granted (actually as soon as an auth code is generated). This is also super easy to implement: starting from the
This interceptor looks for a With this simple change, as soon as you authenticate, the session in the authserver is already dead, so there’s no need to try and manage it from the client. When you log out of the UI app, and then log back in, the
authserver doesn’t recognize you and prompts for credentials. This pattern is the one implemented by the ConclusionIn this section we have seen how to implement a couple of different patterns for logout from an OAuth2 client application (taking as a starting point the application from section five of the tutorial), and some options for other patterns were discussed. These options are not exhaustive, but should give you a good idea of the trade offs involved, and some tools for thinking about the best solution for your use case. There were only couple of lines of JavaScript in this section, and that wasn’t really specific to Angular (it adds a flag to XHR requests), so all the lessons and patterns are applicable beyond the narrow scope of the sample apps in this guide. A recurring theme is that all approaches to single logout (SL) where there are multiple UI apps and a single authserver tend to be flawed in some way: the best you can do is choose the approach that makes your users the least uncomfortable. If you have an internal authserver and a system that is composed of many components, then possibly the only architecture that feels to the user like a single system is a gateway for all user interactions. Want to write a new guide or contribute to an existing one? Check out our contribution guidelines. |