In this section, the source code at https://github.com/laolunsi/spring-boot-examples, please feel free to eat

This section uses Spring Security Oauth2 to implement single sign-on function of SpringBoot project.

Create three SpringBoot applications: Auth-server, client-a, and client-b. Auth-server is the authorization server used for login and obtaining user information.

This section uses SpringBoot 2.1.9.RELEASE and Spring Security 2.1.9.RELEASE


1. Parent project SSO-Oauth2-Demo

First we create a parent Maven project called Sso-Oauth2-Demo. The three applications mentioned above are sub-applications of this project. The parent project Maven introduces the following configuration:

<? The XML version = "1.0" encoding = "utf-8"? > < project XMLNS = "http://maven.apache.org/POM/4.0.0" XMLNS: xsi = "http://www.w3.org/2001/XMLSchema-instance" Xsi: schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion > 4.0.0 < / modelVersion > < groupId > com. Example < / groupId > < artifactId > sso - oauth2 - demo < / artifactId > < version > 1.0 - the SNAPSHOT < / version > < properties > < Java version > 1.8 < / Java version > < spring - the boot version > 2.1.9. RELEASE < / spring - the boot. Version > . < spring ws-security version > 2.1.9. RELEASE < / spring ws-security. Version > < / properties > < dependencies > < the dependency > <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>${spring-security.version}</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement> </project>Copy the code

The parent project has a single Maven pom.xml and requires no code. Let’s start by creating the authorization server and client application A/B


Auth-server authorization server auth-server

Create a sub-Springboot project — Auth-server under the SSO-oAuth2-demo project and introduce the following dependencies:

<? The XML version = "1.0" encoding = "utf-8"? > < project XMLNS = "http://maven.apache.org/POM/4.0.0" XMLNS: xsi = "http://www.w3.org/2001/XMLSchema-instance" Xsi: schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion > 4.0.0 < / modelVersion > < the parent > < groupId > com. Example < / groupId > < artifactId > sso - oauth2 - demo < / artifactId > < version > 1.0 - the SNAPSHOT < / version > < relativePath / > <! -- lookup parent from repository --> </parent> <artifactId> Auth-server </artifactId> <version>0.0.1-SNAPSHOT</version> <name>auth-server</name> <description>Demo project for Spring Boot</description> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>Copy the code

Here we see that the parent sSO-OAuth2-Demo project inherits some common dependencies from the parent project.

Configuration:

server:
  port: 8300
  servlet:
    context-path: '/auth'
Copy the code

PS: The authorization server configuration file is relatively simple and requires nothing else.

Start the class:

@SpringBootApplication
@EnableResourceServer
public class AuthServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(AuthServerApplication.class, args);
    }

}Copy the code

PS: Enable the resource server

There are two classes that need to be configured for Auth and Security:

Authorized server Configuration / * * * * / @ Configuration @ EnableAuthorizationServer public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private BCryptPasswordEncoder passwordEncoder; @Override public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.tokenKeyAccess("permitAll") .checkTokenAccess("isAuthenticated()"); } @Override public void configure(final ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("SampleClientId") .secret(passwordEncoder.encode("secret")) .authorizedGrantTypes("authorization_code") .scopes("user_info") .autoApprove(true) .redirectUris("http://localhost:8301/login", "http://localhost:8302/login"); } // redirectUris must be configured, otherwise an error will be reported when requesting authorization code: error="invalid_request", error_description="At least one redirect_uri must be registered with the client." }Copy the code

PS: BCryptPasswordEncoder If you cannot inject, you can directly try new.

In this demo, the login user name and password are fixed. In the actual project * / @ Configuration @ the Order should be read from the database (1) the public class SecurityConfig extends WebSecurityConfigurerAdapter {@ Override protected void configure(HttpSecurity http) throws Exception { http.requestMatchers() .antMatchers("/login", "/oauth/authorize") .and() .authorizeRequests() .anyRequest() .authenticated() .and() .formLogin() .permitAll() .and().csrf().disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication()  .withUser("eknown") .password(passwordEncoder().encode("123")) .roles("USER"); } @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }}Copy the code

At this point, the basic configuration of the authorization server is complete. Now we need to provide an interface to get login user information:

/** * A unique interface in this interface class, used by ClientA and ClientB to obtain user information after successful login. * This interface address can be arbitrarily modified, */ @restController @requestMapping (value = "user") public class UserAction {RestController @requestMapping (value = "user") public class UserAction { @getMapping (value = "me") public Principal me(Principal Principal) {system.out.println (" call me interface to get user information: "+ Principal); return principal; }}Copy the code

PS: The above interfaces are assigned to ClientA and ClientB and are specified in the configuration to obtain the current user information after login.

Ok, let’s create two test applications — client-A and client-b

Client applications Client-A and client-b

Create SpringBoot projects for maven’s children — client-a and client-b. Here we show the creation and configuration of client-A, and the name of client-b is different.

Modify maven file:

<? The XML version = "1.0" encoding = "utf-8"? > < project XMLNS = "http://maven.apache.org/POM/4.0.0" XMLNS: xsi = "http://www.w3.org/2001/XMLSchema-instance" Xsi: schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion > 4.0.0 < / modelVersion > < the parent > < groupId > com. Example < / groupId > < artifactId > sso - oauth2 - demo < / artifactId > < version > 1.0 - the SNAPSHOT < / version > < relativePath / > <! -- lookup parent from repository --> </parent> <artifactId>client-a</artifactId> <version>0.0.1-SNAPSHOT</version> <name>client-a</name> <description>Demo project for Spring Boot</description> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <! > <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>Copy the code

Configuration, which is more complicated, must be noted:

server: port: 8301 servlet: session: cookie: name: CLIENT_A_SESSION security: oauth2: client: client-id: SampleClientId client-secret: secret access-token-uri: http://localhost:8300/auth/oauth/token user-authorization-uri: http://localhost:8300/auth/oauth/authorize resource: user-info-uri: http://localhost:8300/auth/user/me # currently logged in user information was obtained from the license server address spring: thymeleaf: cache: falseCopy the code

The user-info-URI in the previous auth-server corresponds to the interface.

The startup class does not need to be modified. Here is a configuration class for Security:

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

At this point, the basic configuration is complete. Let’s create the test page and interface:

Create a Templaes folder under the Resources folder, the sibling of application.yml, and place it in two pages:

Index.html:

<! DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Spring Security SSO</title> <link rel="stylesheet" A href = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" / > < / head > < body > < div class = "container" > <div class=" col-SM-12 "> <h1>Spring Security SSO client A</h1> < A class=" BTN bTN-primary "href="securedPage">Login</ A > </div>  </div> </body> </html>Copy the code

securedPage.html:

<! DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Spring Security SSO</title> <link rel="stylesheet" A href = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" / > < / head > < body > < div class = "container" > <div class="col-sm-12"> <h1>Secured Page, Client A</h1> Welcome, <span th:text="${#authentication.name}">Name</span> </div> </div> </body> </html>Copy the code

PS: index.html does not require authentication, whereas securedPage or securedPage uses authentication.name, so authorization is required.

Let’s create the interface to get the page:

@controller public class IndexAction {@getMapping (value = "") public String index() { System.out.println(" Enter ClientA home page "); return "index.html"; } @getMapping (value = "securedPage") public String home() {system.out.println (" enter ClientA securedPage"); return "securedPage.html"; }}Copy the code

Then create the client-b project in the same way as above, noting that some of the client-a and client-b related names or configurations are modified.

With that done, we’re ready to test!


4. Start and test

Start these three projects and run them on port 8300/8301/8302 respectively.

First we go to http://localhost:8301 and go to index.html:

file

Click login, and notice that this interface just opens securedPage.html, and since securedPage.html uses the user information that needs to be authorized, Oauth2 automatically redirected to the auth – the corresponding http://localhost:8300/auth/login server page:

file

Enter the default user name eknow and password 123 to log in:

file

The home page of client-B is displayed:

file

When you click login, instead of being redirected to auth-Server’s login page, you get the user data and go to clientB’s Secured page, indicating that the single sign-on has succeeded!

After ClientA successfully logs in, the ClientB application on the same browser automatically performs authorization authentication and does not need to log in again.

file

Ok, at this point, our SSO-Oauth2-demo project is complete!


Reference:

  1. Simple Single Sign-on With Spring Security OAuth2: www.baeldung.com/sso-spring-…