项目源码: https://github.com/xdouya/Spring-cloud-OAtuh2;
首先介绍一下OAuth2
OAuth2是一个基于令牌的安全验证和授权框架,允许用户使用第三方验证标准服务进行验证.如果用户成功进行了验证,则会出示一个令牌,该令牌必须与每个请求一起发送,然后验证服务可以对令牌进行确认;
OAuth2的主要目的是,在调用多个服务来完成用户请求时,用户不需要在处理请求的时候为每个服务都提供自己的凭据信息就能完成验证.
spring cloud security+ OAuth2实现单点认证鉴权目录结构
- dy-euraka-serivce:euraka服务
- dy-auth-service:OAuth2验证服务器;
- dy-order-service:受保护的资源服务;
父依赖pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</dependencyManagement>
<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>
1. 搭建euraka服务
目录结构
euraka服务的搭建参见源码 https://github.com/xdouya/Spring-cloud-OAtuh2
2. 搭建OAuth2验证服务器
此处着重介绍一下OAtuh2和spring bootsecurity的配置AuthorizationServerConfiguration类和SecurityConfiguration类,其他部分参见源码 https://github.com/xdouya/Spring-cloud-OAtuh2
AuthorizationServerConfiguration.java:注册客户端应用程序,AuthorizationServerConfiguration类定义哪些应用程序可以使用允许访问由OAuth2服务保护的服务;
并设置令牌的存储方式为redis存储,用户的凭据信息和角色信息从mysql数据哭中读写;
package com.dy.oauth.config;
import java.util.concurrent.TimeUnit;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
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.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import com.dy.oauth.dao.UserServiceDetail;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
RedisConnectionFactory redisConnectionFactory;
@Autowired
private DataSource dataSource;
@Autowired
private TokenStore tokenStore;
@Autowired
private UserServiceDetail userServiceDetail;
@Autowired
private ClientDetailsService clientDetailsService;
static final Logger logger = LoggerFactory.getLogger(AuthorizationServerConfiguration.class);
//设置令牌存储方式为redis存储
@Bean
public TokenStore tokenStore() {
return new RedisTokenStore(redisConnectionFactory);
}
// 声明 ClientDetails实现
// 设置用户凭据以及角色从数据库中读取
@Bean
public ClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore).authenticationManager(authenticationManager)
.userDetailsService(userServiceDetail);
// 配置tokenServices参数
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(endpoints.getTokenStore());
tokenServices.setSupportRefreshToken(false);
tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
tokenServices.setAccessTokenValiditySeconds((int)TimeUnit.DAYS.toSeconds(30)); // 30天
endpoints.tokenServices(tokenServices);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
// 允许表单认证
security.allowFormAuthenticationForClients().tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
}
SecurityConfiguration.java:设置[spring boot security的基本属性,允许匿名访问/oauth/**以获取令牌
package com.dy.oauth.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
AuthenticationManager manager = super.authenticationManagerBean();
return manager;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers().anyRequest()
.and()
.authorizeRequests()
.antMatchers("/oauth/**").permitAll();
}
}
应用程序在OAuth2中的注册信息存储在mysql数据库中,可以通过下面贴出的mysql脚步创建相关的应用程序注册信息和创建用来存储用户的凭据和角色信息的用户表和角色表
-- MySQL Script generated by MySQL Workbench
-- 2019年10月16日 星期三 20时39分30秒
-- Model: New Model Version: 1.0
-- MySQL Workbench Forward Engineering
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
-- -----------------------------------------------------
-- Schema oauth2_study
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema oauth2_study
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `oauth2_study` DEFAULT CHARACTER SET utf8 ;
USE `oauth2_study`;
-- ----------------------------
-- Table structure for ClientDetails
-- ----------------------------
DROP TABLE IF EXISTS `ClientDetails`;
CREATE TABLE `ClientDetails` (
`appId` varchar(128) COLLATE utf8_bin NOT NULL,
`resourceIds` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`appSecret` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`scope` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`grantTypes` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`redirectUrl` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`authorities` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additionalInformation` varchar(4096) COLLATE utf8_bin DEFAULT NULL,
`autoApproveScopes` varchar(128) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`appId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Table structure for oauth_access_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_access_token`;
CREATE TABLE `oauth_access_token` (
`token_id` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`token` blob,
`authentication_id` varchar(128) COLLATE utf8_bin NOT NULL,
`user_name` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`client_id` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`authentication` blob,
`refresh_token` varchar(128) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Table structure for oauth_approvals
-- ----------------------------
DROP TABLE IF EXISTS `oauth_approvals`;
CREATE TABLE `oauth_approvals` (
`userId` varchar(128),
`clientId` varchar(128),
`scope` varchar(128),
`status` varchar(10),
`expiresAt` timestamp,
`lastModifiedAt` datetime
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Table structure for oauth_client_details
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(128) COLLATE utf8_bin NOT NULL,
`resource_ids` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`client_secret` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`scope` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`authorized_grant_types` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`web_server_redirect_uri` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`authorities` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` varchar(4096) COLLATE utf8_bin DEFAULT NULL,
`autoapprove` varchar(128) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Records of oauth_client_details
-- ----------------------------
BEGIN;
INSERT INTO `oauth_client_details` VALUES ('client_1', NULL, '{bcrypt}$2a$10$HBX6q6TndkgMxhSEdoFqWOUtctaJEMoXe49NWh8Owc.4MTunv.wXa', 'select', 'client_credentials,refresh_token', NULL, 'oauth2', NULL, NULL, NULL, NULL);
INSERT INTO `oauth_client_details` VALUES ('client_2', '', '{bcrypt}$2a$10$HBX6q6TndkgMxhSEdoFqWOUtctaJEMoXe49NWh8Owc.4MTunv.wXa', 'server', 'password,refresh_token', NULL, 'oauth2', NULL, NULL, NULL, NULL);
COMMIT;
-- ----------------------------
-- Table structure for oauth_client_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_token`;
CREATE TABLE `oauth_client_token` (
`token_id` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`token` blob,
`authentication_id` varchar(128) COLLATE utf8_bin NOT NULL,
`user_name` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`client_id` varchar(128) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Table structure for oauth_code
-- ----------------------------
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
`code` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Table structure for oauth_refresh_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_refresh_token`;
CREATE TABLE `oauth_refresh_token` (
`token_id` varchar(128) COLLATE utf8_bin DEFAULT NULL,
`token` blob,
`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- -----------------------------------------------------
-- Table `oauth2_study`.`user`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `oauth2_study`.`user`;
CREATE TABLE IF NOT EXISTS `oauth2_study`.`user` (
`id` INT NOT NULL AUTO_INCREMENT,
`username` VARCHAR(90) NOT NULL,
`password` VARCHAR(90) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `username_UNIQUE` (`username` ASC))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `oauth2_study`.`role`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `oauth2_study`.`role`;
CREATE TABLE IF NOT EXISTS `oauth2_study`.`role` (
`id` INT NOT NULL,
`rolename` VARCHAR(90) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `rolename_UNIQUE` (`rolename` ASC))
ENGINE = InnoDB;
BEGIN;
INSERT INTO `role` VALUES (2, 'USER');
INSERT INTO `role` VALUES (1, 'ADMIN');
COMMIT;
-- -----------------------------------------------------
-- Table `oauth2_study`.`user_role`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `oauth2_study`.`user_role`;
CREATE TABLE IF NOT EXISTS `oauth2_study`.`user_role` (
`id` INT NOT NULL AUTO_INCREMENT,
`username` VARCHAR(90) NOT NULL,
`rolename` VARCHAR(90) NOT NULL,
PRIMARY KEY (`id`),
INDEX `fk_user_role_1_idx` (`username` ASC),
INDEX `fk_user_role_2_idx` (`rolename` ASC),
CONSTRAINT `fk_user_role_1`
FOREIGN KEY (`username`)
REFERENCES `oauth2_study`.`user` (`username`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_user_role_2`
FOREIGN KEY (`rolename`)
REFERENCES `oauth2_study`.`role` (`rolename`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
3.搭建受保护资源
目录结构
受保护资源的应用程序也就我们平时搭建的业务程序,是一个普通的Spring boot程序,稍有不同在于application.yml配置文件,这里着重介绍一下application.yml,下面贴出代码,其他部分参见源码 https://github.com/xdouya/Spring-cloud-OAtuh2
application.yml:其中security部分填写应用程序在OAuth2服务器上注册的client-id和 client-secret,其中授权方式为passwprd密码授权,应用程序的有效作用域为scope;
spring:
application:
name: service-order
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/oauth2_study?useUnicode=true&characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false
username: root
password: '088114'
server:
port: 8765
eureka:
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://localhost:8761/eureka/
security:
oauth2:
resource:
token-info-uri: http://localhost:9098/oauth/check_token
client:
client-id: client_2
client-secret: 123456
access-token-uri: http://localhost:9098/oauth/token
grant-type: password
scope: server
user-authorization-uri: http://localhost:9098/oauth/authorize
mybatis:
mapper-locations: classpath:mapper/*.xml
以上就成功搭建好了spring cloud security+ OAuth2实现单点认证鉴权项目,下面来进行相关的验证
1.插入用户数据
2.获取令牌
3.通过令牌访问客户端受保护资源
访问需要特定角色的资源
user_1以ADMIN角色注册,因此拥有访问/hello/admin的权限
spring cloud security+ OAuth2源码参见 https://github.com/xdouya/Spring-cloud-OAtuh2;