Spring Cloud OAuth2实现用户认证中心学习笔记

本文案例使用的IDE是Spring Tool Suite 4,当然你如果使用IntelliJIDEA也不会有什么差别

1、创建Spring Cloud OAuth2项目

1、打开Spring Tool Suite 4开发环境,点击File->New->Spring Starter Project,如下图:
在这里插入图片描述
项目的Name:SpringCloudOAuth2Server
Group:wongoing
Artifact:ms
Package:com.wongoing

这些信息都可以根据你的项目实际情况而更改。

2、点击“Next”按钮出现选择项目依赖对话框,如下图:
在这里插入图片描述
此处选择的SpringBoot版本是2.3.8
添加对Cloud OAuth2和Spring Web的依赖
3、点击“Finish”按钮完成项目创建,项目创建完毕后的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.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.8.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>wongoing</groupId>
	<artifactId>ms</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>SpringCloudOAuth2Server</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-oauth2</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

4、默认的项目启动类如下:
com.wongoing.SpringCloudOAuth2ServerApplication.java

package com.wongoing;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringCloudOAuth2ServerApplication {

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

}

2、在不使用数据库的情况下实现AuthenticationServer

1、在项目中创建一个包com.wongoing.oauth2.entity,用于存放相关的实体类。
2、在com.wongoing.oauth2.entity包下创建Role类和User类,其中Role实现org.springframework.security.core.GrantedAuthority接口和java.io.Serializable接口,User实现org.springframework.security.core.userdetails.UserDetails接口和java.io.Serializable接口
代码如下:
com.wongoing.oauth2.entity.Role.java

package com.wongoing.oauth2.entity;

import java.io.Serializable;

import org.springframework.security.core.GrantedAuthority;

public class Role implements GrantedAuthority, Serializable {
	
	private Long id;
	private String name;
	
	public Role() { }
	
	public Role(Long id, String name) {
		this.id = id;
		this.name = name;
	}
	
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return name;
	}
	
	@Override
	public String getAuthority() {
		// TODO Auto-generated method stub
		return name;
	}
}

com.wongoing.oauth2.entity.User.java

package com.wongoing.oauth2.entity;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

public class User implements UserDetails, Serializable {

	private Long id;
	private String username;
	private String password;
	private List<Role> authorities;
	
	public User() { }
	
	public User(Long id, String userName, String password, List<Role> authorities) {
		this.id = id;
		this.username = userName;
		this.password = password;
		this.authorities = authorities;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setAuthorities(List<Role> authorities) {
		this.authorities = authorities;
	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		// TODO Auto-generated method stub
		return this.authorities;
	}

	@Override
	public String getPassword() {
		// TODO Auto-generated method stub
		return this.password;
	}

	@Override
	public String getUsername() {
		// TODO Auto-generated method stub
		return this.username;
	}

	@Override
	public boolean isAccountNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isEnabled() {
		// TODO Auto-generated method stub
		return true;
	}
}

3、在项目中创建一个包com.wongoing.oauth2.config,用于存放与AuthenticationServer相关的配置类。
3.1 在com.wongoing.oauth2.config包下创建DefaultPaswordConfig.java,代码如下:
com.wongoing.oauth2.config.DefaultPassowrdConfig.java

package com.wongoing.oauth2.config;

import java.io.Serializable;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * 功能说明:定义默认密码工具类
 * 修改说明:
 * @author zheng
 * @date 2021-1-19 15:54:22
 * @version 0.1
 */
@Component
public class DefaultPasswordConfig extends BCryptPasswordEncoder implements Serializable {

}

3.2 在com.wongoing.oauth2.config包下创建DefaultTokenStoreConfig.java,代码如下:
com.wongoing.oauth2.config.DefaultTokenStoreConfig.java

package com.wongoing.oauth2.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

/**
 * 功能说明:TokenStore工具类
 * 修改说明:
 * @author zheng
 * @date 2021-1-19 16:48:46
 * @version 0.1
 */
@Configuration
public class DefaultTokenStoreConfig {
	
	@Bean
	public TokenStore tokenStore() {
		//将Token存储在内存中
		return new InMemoryTokenStore();
	}
}

3.3 在com.wongoing.oauth2.config包下创建UserDetailsServiceBean.java,代码如下:
com.wongoing.oauth2.config.UserDetailsServiceBean.java

package com.wongoing.oauth2.config;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import com.wongoing.oauth2.entity.Role;
import com.wongoing.oauth2.entity.User;

/**
 * 功能说明:用户服务类
 * 修改说明:
 * @author zheng
 * @date 2021-1-19 14:53:26
 * @version 0.1
 */
@Component
public class UserDetailsServiceBean implements UserDetailsService, Serializable {

	@Autowired
	private PasswordEncoder passwordEncoder;
	
	//保存用户测试数据
	private Map<String, User> users = null;
	
	/**
	 * 功能说明:通过@PostConstruct定义Bean初始化方法
	 * 修改说明:
	 * @author zheng
	 * @date 2021-1-19 16:39:55
	 */
	@PostConstruct
	public void init() {
		//生成测试数据		
		this.users = new HashMap<String, User>() {{
			put("admin", new User(1L, "admin", passwordEncoder.encode("456"), new ArrayList() {{ add(new Role(1L, "ADMIN")); }}));
			put("zheng", new User(2L, "zheng", passwordEncoder.encode("789"), new ArrayList() {{ add(new Role(2L, "USER")); }}));
		}};
	}
	
	/**
	 * 根据用户名获取用户详情 
	 */
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		//后期可以通过注入UserDao,使用UserDao从数据库中查找用户
		if (this.users.containsKey(username)) {
			return this.users.get(username);
		}
		return null;
	}
}

3.4 在com.wongoing.oauth2.config包下创建WebSecurityConfig类并继承org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter,代码如下:
com.wongoing.oauth2.config.WebSecurityConfig.java

package com.wongoing.oauth2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * 功能说明:Web安全配置类(Spring Cloud OAuth2中强制要求使用此类)
 * 修改说明:
 * @author zheng
 * @date 2021-1-19 15:58:43
 * @version 0.1
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
			.anyRequest().authenticated()
			.and()
			.formLogin()
			.and()
			.csrf().disable()
			.httpBasic();
		
	}
	
	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/favor.ioc");		//配置/favor.ioc不需要进行安全拦截
	}
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService).passwordEncoder(this.passwordEncoder);
	}	
	
	/**
	 * 这一步的配置是必不可少的,否则SpringBoot会自动配置一个AuthenticationManager,覆盖掉内存中的用户
	 * @return 认证管理对象
	 */
	@Override
	@Bean
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}
}

3.5 在com.wongoing.oauth2.config包下创建AuthorizationServerConfig类并继承org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;,代码如下:
com.wongoing.oauth2.config.AuthorizationServerConfig

package com.wongoing.oauth2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
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.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private TokenStore tokenStore;
	
	@Autowired
	private AuthenticationManager authenticationManager;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		// 将客户端的信息存储在内存中
		// 此处客户端信息先写死,后面会写一个从数据库中读取客户端信息的例子
		clients.inMemory()
			.withClient("client1")
			.secret(this.passwordEncoder.encode("123456"))
			.authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token", "password")		//此处设置支持4种授权类型
			.redirectUris("http://www.baidu.com")
			.scopes("all");
	}
	
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		// 配置Token的存储方式
		endpoints.tokenStore(this.tokenStore)
			// 注入WebSecurityConfig配置的bean
			.authenticationManager(authenticationManager)
			// 读取用户的验证信息
			.userDetailsService(userDetailsService)
			//配置允许通过GET请求获取access_token
			.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
	}
	
	
	@Override
	public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
		// 对获取Token的请求不再拦截
		oauthServer
			.tokenKeyAccess("permitAll()")
			// 验证获取Token的验证信息
			.checkTokenAccess("isAuthenticated()")
			//这个如果配置支持allowFormAuthenticationForClients的,且对/oauth/token请求的参数中有client_id和client-secret的会走ClientCredentialsTokenEndpointFilter来保护
			//如果没有支持allowFormAuthenticationForClients或者有支持但对/oauth/token请求的参数中没有client_id和client_secret的,走basic认证保护
			.allowFormAuthenticationForClients();
	}
}

3、测试AuthenticationServer

我们通过Spring Cloud OAuth2的2个端点来进行验证测试
端点1:/oauth/authorize,此端点用于获取授权码code
端点2:/oauth/token,此端点用于获取access_token

3.1 授权码方式(grant_type=authorization_code)验证测试

1、首先通过项目入口程序启动此Spring Boot项目。
2、通过oauth/authorize端点获取授权码,打开浏览器在地址栏输入:

http://localhost:8080/oauth/authorize?response_type=code&client_id=client1&client_secret=123456&redirect_uri=http://www.baidu.com

如下图:
第一次进入登录页面,如下:
在这里插入图片描述
3、输入用户名admin,密码456,然后点击Sign in,如下以下界面
在这里插入图片描述
4、选择Approve,然后点击Authorize,会进入redirect_uri,如下图:
在这里插入图片描述

从上图中可以得到code的值
5、使用授权码获取access_token,打开postman,输入地址如下:

http://localhost:8080/oauth/token?grant_type=authorization_code&code=ISEM95&redirect_uri=http://www.baidu.com&client_id=client1&client_secret=123456

如下图:
在这里插入图片描述

3.2 客户端方式(grant_type=client_credentials)验证测试

1、在postman中输入以下地址进行访问:

http://localhost:8080/oauth/token?grant_type=client_credentials&client_id=client1&client_secret=123456

如下图:
在这里插入图片描述

3.3 用户名密码方式(grant_type=password)验证测试

1、在postman中输入以下地址进行访问:

  • http://localhost:8080/oauth/token?grant_type=password&client_id=client1&client_secret=123456&username=admin&password=456
  • http://localhost:8080/oauth/token?grant_type=password&client_id=client1&client_secret=123456&username=zheng&password=789

如下图:
在这里插入图片描述
在这里插入图片描述

3.4 刷新token(grant_type=refresh_token)测试

1、在postman中输入以下地址进行访问

http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client1&client_secret=123456&refresh_token=31b124a6-d4cf-48e3-9800-39f80d4443b2

如下图:
在这里插入图片描述

4、不使用数据库版本的AuthorizationServer源码下载

不使用数据库版本的AuthorizationServer源码下载

5、基于数据库的情况下实现AuthenticationServer

5.1 创建oauth2相关表

可以参考官方建议的表结构,地址如下:
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql
以下是整理的mysql版本的建表语句

CREATE TABLE oauth_client_details (
  client_id VARCHAR(256) PRIMARY KEY,
  resource_ids VARCHAR(256),
  client_secret VARCHAR(256),
  scope VARCHAR(256),
  authorized_grant_types VARCHAR(256),
  web_server_redirect_uri VARCHAR(256),
  authorities VARCHAR(256),
  access_token_validity INTEGER,
  refresh_token_validity INTEGER,
  additional_information VARCHAR(4096),
  autoapprove VARCHAR(256)
);
 
 
CREATE TABLE oauth_client_token (
  token_id VARCHAR(256),
  token BLOB,
  authentication_id VARCHAR(25) PRIMARY KEY,
  user_name VARCHAR(256),
  client_id VARCHAR(256)
);
 
CREATE TABLE oauth_access_token (
  token_id VARCHAR(256),
  token BLOB,
  authentication_id VARCHAR(250) PRIMARY KEY,
  user_name VARCHAR(256),
  client_id VARCHAR(256),
  authentication BLOB,
  refresh_token VARCHAR(256)
);
 
CREATE TABLE oauth_refresh_token (
  token_id VARCHAR(256),
  token BLOB,
  authentication BLOB
);
 
CREATE TABLE oauth_code (
  CODE VARCHAR(256), authentication BLOB
);
 
CREATE TABLE oauth_approvals (
    userId VARCHAR(256),
    clientId VARCHAR(256),
    scope VARCHAR(256),
    STATUS VARCHAR(10),
    expiresAt TIMESTAMP,
    lastModifiedAt TIMESTAMP
);
 
 
-- customized oauth_client_details table
CREATE TABLE ClientDetails (
  appId VARCHAR(256) PRIMARY KEY,
  resourceIds VARCHAR(256),
  appSecret VARCHAR(256),
  scope VARCHAR(256),
  grantTypes VARCHAR(256),
  redirectUrl VARCHAR(256),
  authorities VARCHAR(256),
  access_token_validity INTEGER,
  refresh_token_validity INTEGER,
  additionalInformation VARCHAR(4096),
  autoApproveScopes VARCHAR(256)
);

创建一个mysql的数据库,然后在数据中执行上面的建表语句。

5.2 在数据表中增加client的定义

INSERT INTO oauth_client_details(client_id,client_secret,scope,authorized_grant_types,web_server_redirect_uri) VALUES('webApp','$2a$10$CgTKlYAXYJeWX9Zem3hCSutmSjA2DrwDiPW5ta/qRO2Gv3Pk/n2yC','all','authorization_code,password,refresh_token,client_credentials','http://www.baidu.com');
INSERT INTO oauth_client_details(client_id,client_secret,scope,authorized_grant_types) VALUES('app','$2a$10$6vUDS.ai.Szi.S6vU/8nluoa.JoOJagy9G4ak4yBxjdbJlDJQTD1.','all','password,refresh_token');

上面的第1条记录的client_secret值是123,第2条记录的client_secret的值是456。

5.3 修改pom.xml增加以下依赖,这里使用了阿里的druid数据库连接池

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid-spring-boot-starter</artifactId>
	<version>1.2.4</version>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>

这样完整的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.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.8.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>wongoing</groupId>
	<artifactId>ms</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>SpringCloudOAuth2Server</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-oauth2</artifactId>
		</dependency>
		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.4</version>
        </dependency>
        <dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

5.4 把application.properties修改为application.yml,增加数据源的相关配置

application.yml内容如下:

spring:
  datasource:
    name: dataSource
    url: jdbc:mysql://localhost:3306/wcm_uaa?useUnicode=true&characterEncoding=utf-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
    username: uid
    password: ******
    driver-class-name: com.mysql.cj.jdbc.Driver
    ###################以下为druid增加的配置###########################
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      db-type: mysql
      # 下面为连接池的补充设置,应用到上面所有数据源中
      # 初始化大小,最小,最大
      initial-size: 5
      # 最小连接池数量
      min-idle: 5
      # 最大连接池数量
      max-active: 20
      # 配置获取连接等待超时的时间
      max-wait: 60000
      #申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
      test-while-idle: true
      #既作为检测的间隔时间又作为testWhileIdel执行的依据
      time-between-eviction-runs-millis: 60000
      #销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接
      min-evictable-idle-time-millis: 30000
      #用来检测连接是否有效的sql 必须是一个查询语句
      #mssql中为 select 1
      #mysql中为 select 'x'
      #oracle中为 select 1 from dual
      validation-query: select 1
      #申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
      test-on-borrow: false
      #归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
      test-on-return: false
      #当数据库抛出不可恢复的异常时,抛弃该连接
      #exception-sorter: true
      #是否缓存preparedStatement,mysql5.5+建议开启
      pool-prepared-statements: true
      #当值大于0时poolPreparedStatements会自动修改为true
      max-pool-prepared-statement-per-connection-size: 20
      #配置扩展插件
      #配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
      filters: stat,wall,slf4j
      #通过connectProperties属性来打开mergeSql功能;慢SQL记录
      connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
      #合并多个DruidDataSource的监控数据
      use-global-data-source-stat: true
      #设置访问druid监控页的账号和密码,默认没有
      stat-view-servlet:
        login-username: admin
        login-password: admin
        enabled: true
      #开启web filter
      web-stat-filter:
        enabled: true
###############以上为配置druid添加的配置#######################################

5.5 修改DefaultTokenStoreConfig为数据库存储Token

修改后的com.wongoing.oauth2.config.DefaultTokenStoreConfig.java代码如下:

package com.wongoing.oauth2.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

/**
 * 功能说明:TokenStore工具类
 * 修改说明:
 * @author zheng
 * @date 2021-1-19 16:48:46
 * @version 0.1
 */
@Configuration
public class DefaultTokenStoreConfig {
	
	@Autowired
	private DataSource dataSource;
	
	@Bean
	public TokenStore tokenStore() {
		//将Token存储在内存中
//		return new InMemoryTokenStore();
		//将Token存储在数据库中
		return new JdbcTokenStore(this.dataSource);
	}
}

5.7 删除原来的AuthorizationServerConfig类

删除com.wongoing.oauth2.config.AuthorizationServerConfig.java或者注释掉类前面的2个注解,注释掉注解后的代码如下

package com.wongoing.oauth2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
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.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;

//@Configuration
//@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private TokenStore tokenStore;
	
	@Autowired
	private AuthenticationManager authenticationManager;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		// 将客户端的信息存储在内存中
		// 此处客户端信息先写死,后面会写一个从数据库中读取客户端信息的例子
		clients.inMemory()
			.withClient("client1")
			.secret(this.passwordEncoder.encode("123456"))
			.redirectUris("http://www.baidu.com")
			.authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token", "password")		//此处设置支持4种授权类型
			.scopes("all");
	}
	
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		// 配置Token的存储方式
		endpoints.tokenStore(this.tokenStore)
			// 注入WebSecurityConfig配置的bean
			.authenticationManager(authenticationManager)
			// 读取用户的验证信息
			.userDetailsService(userDetailsService)
			//配置允许通过GET请求获取access_token
			.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
	}
	
	
	@Override
	public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
		// 对获取Token的请求不再拦截
		oauthServer
			.tokenKeyAccess("permitAll()")
			// 验证获取Token的验证信息
			.checkTokenAccess("isAuthenticated()")
			//这个如果配置支持allowFormAuthenticationForClients的,且对/oauth/token请求的参数中有client_id和client-secret的会走ClientCredentialsTokenEndpointFilter来保护
			//如果没有支持allowFormAuthenticationForClients或者有支持但对/oauth/token请求的参数中没有client_id和client_secret的,走basic认证保护
			.allowFormAuthenticationForClients();
	}
}

5.8 增加AuthorizationServerConfigByDataSource.java类

在com.wongoing.oauth2.config包下创建AuthorizationServerConfigByDataSource类并继承AuthorizationServerConfigurerAdapter,代码如下:
com.wongoing.oauth2.config.AuthorizationServerConfigByDataSource.java

package com.wongoing.oauth2.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
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.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfigByDataSource extends AuthorizationServerConfigurerAdapter {
	
	@Autowired
	private DataSource dataSource;
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private TokenStore tokenStore;
	
	@Autowired
	private AuthenticationManager authenticationManager;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		clients.jdbc(this.dataSource);		//会从数据库的oauth_client_details表中获取client的定义
	}
	
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints.tokenStore(this.tokenStore)
			.authenticationManager(this.authenticationManager)
			.userDetailsService(this.userDetailsService)
			.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);			//允许使用GET请求访问/oauth/token端点
	}
	
	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		security.tokenKeyAccess("permitAll()")
			.checkTokenAccess("isAuthenticated")
			.allowFormAuthenticationForClients();
	}
	
	@Bean
	public AuthenticationProvider daoAuthenticationProvider() {
		DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
		daoAuthenticationProvider.setUserDetailsService(userDetailsService);
		daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
		daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
		return daoAuthenticationProvider;
	}
}

6、测试基于数据库实现的AuthenticationServer

基于数据库实现的验证服务器在测试时传递的client_id和client_secret参数一定要与oauth_client_details表中的数据对应上

在这里插入图片描述

6.1 授权码方式(grant_type=authorization_code)验证测试

1、首先通过项目入口程序启动此Spring Boot项目。
2、通过oauth/authorize端点获取授权码,打开浏览器在地址栏输入:

http://localhost:8080/oauth/authorize?response_type=code&client_id=webApp&client_secret=123&redirect_uri=http://www.baidu.com

后续步骤参照3.1的步骤进行测试。

6.2 客户端方式(grant_type=client_credentials)验证测试

1、在postman中输入以下地址进行访问:

http://localhost:8080/oauth/token?grant_type=client_credentials&client_id=webApp&client_secret=123

如下图:
在这里插入图片描述
同时在数据库中查询oauth_access_token,可以看到token已经存到数据表中了,如下图:
在这里插入图片描述

6.3 用户名密码方式(grant_type=password)验证测试

1、在postman中输入以下地址进行访问:

  • http://localhost:8080/oauth/token?grant_type=password&client_id=webApp&client_secret=123&username=admin&password=456
  • http://localhost:8080/oauth/token?grant_type=password&client_id=app&client_secret=456&username=zheng&password=789

如下图:
在这里插入图片描述
在这里插入图片描述

6.4 刷新token(grant_type=refresh_token)测试

1、在postman中输入以下地址进行访问

http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=webApp&client_secret=123&refresh_token=af9bb496-290d-431e-a2f4-f4000f3bc390

如下图:
在这里插入图片描述

7、基于数据库版本的AuthorizationServer源码下载

基于数据库版本的AuthorizationServer源码下载

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页