Learning Spring Security (8): Using Spring Security OAuth2 to achieve single sign-on

1 Overview

In this tutorial, we will discuss how to implement SSO (single sign-on) using Spring Security OAuth and Spring Boot.

This example will use three separate applications

  • An authorization server (central authentication mechanism)

  • Two client applications (applications that use SSO)

In a nutshell, when a user tries to access a secure page of a client app, they are first authenticated through an authentication server redirect.

We will use the Authorization Code grant type from OAuth2 to drive authorization.

2. Client application

Let's start with the client application and use Spring Boot to minimize the configuration:

2.1. Maven dependencies

First, the following dependencies need to be added to pom.xml:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.security.oauth</groupId><artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency> 

2.2. Security configuration

Next, the most important part is the security configuration of the client application:

@Configuration
@EnableOAuth2Sso
public class UiSecurityConfig extends WebSecurityConfigurerAdapter { @Overridepublic void configure(HttpSecurity http) throws Exception {http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**").permitAll().anyRequest().authenticated();}
} 

Of course, the core part of this configuration is the @EnableOAuth2Sso annotation, which we use to enable single sign-on.

Note that we need to subclass WebSecurityConfigurerAdapter — without it, all paths will be secured — so users will be redirected to the login page when they try to access any page. In the current example, the index page and login page can be accessed without authentication.

Finally, we also define a RequestContextListener bean to handle requests.

application.yml:

server:port: 8082context-path: /uisession:cookie:name: UISESSION
security:basic:enabled: falseoauth2:client:clientId: SampleClientIdclientSecret: secretaccessTokenUri: http://localhost:8081/auth/oauth/tokenuserAuthorizationUri: http://localhost:8081/auth/oauth/authorizeresource:userInfoUri: http://localhost:8081/auth/user/me
spring:thymeleaf:cache: false 

There are a few points to explain :

  • We disabled the default Basic Authentication

  • accessTokenUri is the URI to get the access token

  • userAuthorizationUri is the authorization URI the user will be redirected to

  • The user endpoint userInfoUri URI is used to get the details of the current user

In addition, it should be noted that in this example, we used the authorization server built by ourselves. Of course, we can also use the authorization server of other third-party providers, such as Facebook or GitHub.

2.3. Front end

Now let's look at the front-end configuration of the client application. We don't want to spend too much time here, mainly because it's been covered before .

The client application has a very simple front end:

index.html

<h1>Spring Security SSO</h1>
<a href="securedPage">Login</a> 

securedPage.html

<h1>Secured Page</h1>
Welcome, <span th:text="${#authentication.name}">Name</span> 

The securedPage.html page requires user authentication. If an unauthenticated user tries to access securedPage.html, they will first be redirected to the login page.

3. Authentication server

Now let's start talking about the authorization server.

3.1. Maven dependencies

First, define dependencies in pom.xml:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.security.oauth</groupId><artifactId>spring-security-oauth2</artifactId>
</dependency> 

3.2. OAuth configuration

It's important to understand why we're running the authorization server and the resource server together as a single deployable unit here.

Let's start by configuring the resource server:

@SpringBootApplication
@EnableResourceServer
public class AuthorizationServerApplication extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication.run(AuthorizationServerApplication.class, args);}
} 

After that, configure the authorization server:

@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate AuthenticationManager authenticationManager;
 @Overridepublic void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");}
 @Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient("SampleClientId").secret("secret").authorizedGrantTypes("authorization_code").scopes("user_info").autoApprove(true) ; }
 @Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager);}
} 

Note that we use the authorization_code authorization type to start a simple client.

3.3. Security Configuration

First, we'll disable the default Basic Authentication via application.properties:

server.port=8081
server.context-path=/auth
security.basic.enabled=false 

Now, let's go to configuration and define a simple form login mechanism:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 @Autowiredprivate AuthenticationManager authenticationManager;
 @Overrideprotected void configure(HttpSecurity http) throws Exception {http.requestMatchers().antMatchers("/login", "/oauth/authorize").and().authorizeRequests().anyRequest().authenticated().and().formLogin().permitAll();}
 @Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.parentAuthenticationManager(authenticationManager).inMemoryAuthentication().withUser("john").password("123").roles("USER");}
} 

Note that while we used simple in-memory authentication, it could be easily replaced with a custom userDetailsService.

3.4. User endpoint

Finally, we'll create the user endpoint we used earlier in the configuration:

@RestController
public class UserController {@GetMapping("/user/me")public Principal user(Principal principal) {return principal;}
} 

User data will be returned as JSON.

4 Conclusion

In this quick tutorial, we implemented single sign-on using Spring Security Oauth2 and Spring Boot.

As always, you can find the full source code on GitHub .

Original project sample code

github.com/eugenp/tuto…

Guess you like

Origin blog.csdn.net/qq_44005305/article/details/128561170#comments_25802422