环境:VMWindows10+IDEA+JDK8+Maven+SpringBoot+SpringSecurity+oauth2
实现:统一认证端sso_oauth2 (8080)双客户端sso_client_demo1(8081)+
sso_client_demo2(8082),实现单点入门例子,一处登录多处登录。
源码:
目录
二、Maven 父工程 sso_spring_security创建
三、在父工程 sso_spring_security 中创建子工程(Module)sso_oauth2,统一认证平台
四、客户端Demo01子工程sso_client_demo1创建
五、客户端Demo02子工程sso_client_demo2创建
一、实现结果
1、服务程序结构及端口
2、 Demo1客户端登录
3、点击Login自动跳转到8080统一登录认证页面
4、输入账号/密码,Sign in到 Demo1客户端页面
5、 修改访问地址为8082,此时不需要重新调整到步骤3中的登录认证界面,默认认证成功
二、Maven 父工程 sso_spring_security创建
只依赖Security、oauth2-autoconfigure,不需要其他,包括不需要web;pom.xml如下:
<?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>org.sso</groupId>
<artifactId>sso_spring_security</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<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>
三、在父工程 sso_spring_security 中创建子工程(Module)sso_oauth2,统一认证平台
1、pom.xml内容如下,注意点:指定父工程;需与父工程中的 <groupId><artifactId><version>保持一致;
<?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>
<parent>
<groupId>org.sso</groupId>
<artifactId>sso_spring_security</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath/> <!-- 指定父工程,引用父工程依赖 -->
</parent>
<artifactId>sso_oauth2</artifactId>
<version>1.0-SNAPSHOT</version>
<name>sso_oauth2</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>
2、application.yml指定端口,路径标识
server:
port: 8080
servlet:
context-path: '/auth'
3、启动类SsoOauth2Application增加@EnableResourceServer注解
package com.sso.sso_oauth2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
@SpringBootApplication
@EnableResourceServer
public class SsoOauth2Application {
public static void main(String[] args) {
SpringApplication.run(SsoOauth2Application.class, args);
}
}
@EnableResourceServer是为OAuth2资源服务器提供方便的注释,启用Spring Security 过滤器,通过传入的OAuth2令牌对请求进行身份验证。
3、新建AuthServerConfig授权服务器配置
package com.sso.sso_oauth2.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
/**
* 授权服务器配置
* 必须进行redirectUris的配置,否则请求授权码时会报错:error="invalid_request", error_description="At least one redirect_uri must be registered with the client."
* withClient 与客户端 client-id 一致
*/
@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:8081/login", "http://localhost:8082/login");
}
}
4、新建 SecurityConfig security基本配置,并指定登录用户名与密码是固定的,实际项目中应该从数据库读取
package com.sso.sso_oauth2.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* security基本配置
* 本demo中,登录用户名与密码是固定的,实际项目中应该从数据库读取
*/
@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("admin")
.password(passwordEncoder().encode("123456"))
.roles("USER");
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
5、新建UserController
package com.sso.sso_oauth2.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
/**
* 该接口类中的唯一接口,用于Client01和Client02在登录成功后获取用户信息用
* 该接口地址可以任意修改,只要与Client01/02中配置的用户信息地址一致即可
*/
@RestController
@RequestMapping(value = "user")
public class UserController {
@GetMapping(value = "userInfo")
public Principal me(Principal principal) {
System.out.println("调用userInfo接口获取用户信息:" + principal);
return principal;
}
}
四、客户端Demo01子工程sso_client_demo1创建
1、pom.xml依赖内容如下,同认证平台,需指定父工程
<?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>
<parent>
<groupId>org.sso</groupId>
<artifactId>sso_spring_security</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.sso</groupId>
<artifactId>sso_client_demo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sso_client_demo1</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<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和thymeleaf security的依赖 -->
<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>
2、新建MySecurityConfig
package com.sso.sso_client_demo1.config;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableOAuth2Sso
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/", "/login**")
.permitAll()
.anyRequest()
.authenticated();
}
}
3、页面跳转IndexController
package com.sso.sso_client_demo1.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
/**
* 获取页面的接口
*/
@Controller
public class IndexController {
@GetMapping(value = "")
public String index() {
System.out.println("进入Client01首页");
return "index.html";
}
@GetMapping(value = "securedPage")
public String home() {
System.out.println("进入Client01 securedPage");
return "securedPage.html";
}
}
4、启动类不动SsoClientDemo1Application
package com.sso.sso_client_demo1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SsoClientDemo1Application {
public static void main(String[] args) {
SpringApplication.run(SsoClientDemo1Application.class, args);
}
}
5、客户端首页
<!DOCTYPE html>
<html lang="en">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>Spring Security SSO</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"
rel="stylesheet" />
</head>
<body>
<div class="container">
<div class="col-sm-12">
<h1>Spring Security SSO 客户端 Demo01</h1>
<a class="btn btn-primary" href="securedPage">Login</a>
</div>
</div>
</body>
</html>
6、客户端Demo01访问成功页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>Spring Security SSO</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"
rel="stylesheet" />
</head>
<body>
<div class="container">
<div class="col-sm-12">
<h1>Secured Page, Client Demo01</h1>
Welcome, <span th:text="${#authentication.name}">Name</span>
</div>
</div>
</body>
</html>
7、客户端Demo01配置文件 application.yml,,注意cookie name保持唯一;client-id,client-secret与认证工程三-3中参数保持一致;路由参数IP:PORT指定认证平台参数
server:
port: 8081
servlet:
session:
cookie:
name: CLIENT_1_SESSION
security:
oauth2:
client:
client-id: SampleClientId
client-secret: secret
access-token-uri: http://localhost:8080/auth/oauth/token
user-authorization-uri: http://localhost:8080/auth/oauth/authorize
resource:
user-info-uri: http://localhost:8080/auth/user/userInfo
spring:
thymeleaf:
cache: false
五、客户端Demo02子工程sso_client_demo2创建
1、同理步骤四,需注意参数的修改