項目源碼: 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;