Angular 2 login with spring security
im trying to integrate spring security with angular 2 custom name, that is, my application endpoint secured with spring security, trying to access it will be redirected to / login which is handled in angular 2. Currently i don't know how sign in and provide access to the API after registration.
I am configuring spring security like this:
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors().and()
.authorizeRequests()
.antMatchers("/api/someEndpoint/**")
.hasRole(ADMIN_ROLE).and().formLogin()
.loginPage("/login").and().logout();
}
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
since I had a default login, everything worked fine, but I found I could not create a working angular 2 login integration. I tried the following code in angular 2 to no avail:
login(loginDetails:Object) {
console.log(loginDetails)
const headers = new Headers({ 'Content-Type': 'application/json' });
const options = new RequestOptions({ headers: headers });
const body = JSON.stringify(loginDetails);
console.log(headers);
console.log(body);
return this.http.post(this.loginUrl, body, options)
}
as far as I know spring defaults for username and password names "username" and "password" which I am pretty sure are passed in the request body, so passing some invalid user data like {"username":"admin", "password" : "pass"}
I have to be redirected to / login ? Error or whatever, and on successful authentication I should be redirected to / welcome and remain authenticated
I have user and password defined in my db and my custom UserDetailsService checks against it any answers, comments or questions are welcome
source to share
Once you work with the API, you should be using HTTP Basic or an authentication token, not Form one. HTTPS is required when using any of these.
For HTTP Basic authorization using Angular 2, the login service might look like this:
login (loginDetails: any): Observable<LoginResponse> { // custom class, may be empty for now
let headers = new Headers({
'Authorization': 'Basic ' + btoa(loginDetails.login + ':' + loginDetails.pass),
'X-Requested-With': 'XMLHttpRequest' // to suppress 401 browser popup
});
let options = new RequestOptions({
headers: headers
});
return this
.http
.post(this.loginUrl, {}, options)
.catch(e => this.handleError(e); // handle 401 error - bad credentials
}
... then you can subscribe to this in the component:
loginNow() {
this
.loginService
.login(this.loginDetails)
.subscribe(next => {
this.router.navigateByUrl("/"); // login succeed
}, error => {
this.error = "Bad credentials"; // or extract smth from <error> object
});
}
Then you can use the method loginNow()
inside component templates like (click)="loginNow()
.
Once the server accepts authorization, it JSESSIONID
will be automatically saved in your browser due to Spring Security features, and you don't have to send credentials every time to access private resources.
Your server login method might look like this:
@PreAuthorize("hasRole('USER')")
@PostMapping("/login")
public ResponseEntity login() {
return new ResponseEntity<>(HttpStatus.OK);
}
... it will be rejected with 401 UNAUTHORIZED
if authorization fails, or accepted with 200 SUCCESS
if it doesn't.
How to properly configure the server in a number of Spring Security demo projects - https://github.com/spring-guides/tut-spring-security-and-angular-js
code untested though :(
source to share
Your spring security config should look like this
http!!
.cors().and()
.csrf().disable()
.authorizeRequests()
.requestMatchers(object: RequestMatcher {
override fun matches(request: HttpServletRequest?): Boolean {
return CorsUtils.isCorsRequest(request)
}
}).permitAll()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll()
.and()
.formLogin().permitAll()
source to share