This section source inGithub.com/laolunsi/sp…Please rest assured 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:


      
<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-boot.version>2.1.9. RELEASE</spring-boot.version>
        <spring-security.version>2.1.9. RELEASE</spring-security.version>
    </properties>

    <dependencies>
        <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:


      
<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>
    <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 - the 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:

/** * Authorization 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 actual projects, the login user name and password should be read from the database
@Configuration
@Order(1)
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(a) {
        return newBCryptPasswordEncoder(); }}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 modified as long as it is the same as the user information address configured in ClientA/B */
@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);
        returnprincipal; }}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:


      
<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>
    <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 - the 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>

        <! Thymeleaf and thymeleaf security dependencies
        <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 The address to get the current login user information from the authorization server

spring:
  thymeleaf:
    cache: false
Copy 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:

<! DOCTYPEhtml>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Spring Security SSO</title>
<link rel="stylesheet"
	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:

<! DOCTYPEhtml>
<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"
	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:

/** * Get the page interface */
@Controller
public class IndexAction {

    @GetMapping(value = "")
    public String index(a) {
        System.out.println("Enter ClientA home page");
        return "index.html";
    }

    @GetMapping(value = "securedPage")
    public String home(a) {
        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:

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:

Enter the default username eknown and password 123 to log in:

The home page of client-B is displayed:

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.

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-…

Finally, welcome to pay attention to my official account: Language of ape Biology, search keywords or scan code: