Filter
based solution for Servlet applicationsSub-text: "use them, they’re reliable and free".
Filter
(c.f. "basic": https://github.com/…/basic, Part I)
index.html
<html>
...
<body ng-app="hello">
<div class="container">
<h1>Greeting</h1>
<div ng-controller="home as home" ng-cloak class="ng-cloak">
<p>The ID is: {{home.greeting.id}}</p>
<p>The content is: {{home.greeting.msg}}</p>
</div>
</div>
<script src="js/angular-bootstrap.js" type="text/javascript"></script>
<script src="js/hello.js"></script>
</body>
</html>
hello.js
angular.module('hello', [])
.controller('home', function($http) {
var self = this;
$http.get('/resource/').then(function(response) {
self.greeting = response.data;
})
}
);
With Spring Boot you get a secure application out of the box, but it is easy to customize for a custom user details store (e.g. directory).
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
or build.gradle
dependencies {
compile('org.springframework.boot:spring-boot-starter-security')
}
To be able to add a login form to the app we need to make some HTML static resources accessible anonymously
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/index.html", "/home.html",
"/login.html", "/").permitAll()
.anyRequest().authenticated();
}
}
(c.f. "single": https://github.com/…/single, Part I)
So:
angular.module('hello', []).config(function($httpProvider) {
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
})
...
<form role="form" ng-submit="controller.login()">
...
</form>
self.credentials = {};
self.login = function() {
$http.get('/user', {
headers : { authorization : "Basic "
+ btoa(self.credentials.username
+ ":" + self.credentials.password)
}}).then(function(response) {
self.greeting = response.data;
self.show = false;
})
}
login()
function sends HTTP Basic credentials and checks the "/user" endpoint.(c.f. "single": https://github.com/…/single, Part II)
To Client | Name | From Client | Name | |
---|---|---|---|---|
Spring Security |
Request attribute |
_csrf |
Request header |
X-CSRF-TOKEN |
Angular JS |
Cookie |
XSRF-TOKEN |
Request header |
X-XSRF-TOKEN |
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
(c.f. "vanilla": https://github.com/…/vanilla, Part III)
Use @CrossOrigin
on your @RequestMapping
and this:
public class ResourceApplication extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
...
}
there is also CorsUtils::isCorsRequest method you can use in a
request matcher.
|
(c.f. "spring-session": https://github.com/…/spring-session, Part III)
(c.f. "proxy": https://github.com/…/proxy, Part IV)
(c.f. "oauth2": https://github.com/…/oauth2, Part V)
(c.f. "double": https://github.com/…/double, Part VI)
Imagine several physical implementations of the same system with an identical Javascript client (single page application) and a secure back end. Application and security architecture variations:
Application | Description | Security | Blog |
---|---|---|---|
|
Single backend |
HTTP Basic |
Part I |
|
Adds form authentication |
Session cookie |
Part II |
|
Adds secure backend with custom token |
Spring Session ID as token |
Part III |
|
UI acts as proxy. |
Session cookie, Spring Session |
Part IV |
|
Add OAuth2 SSO with a separate authentication server |
Session cookie in UI and access token for backends |
Part V |
|
Add "admin" UI behind Gateway |
Session cookie, Spring Session |
Part VI |
@EnableZuulProxy
)/