Springcloud + OAuth2 + Spring boot Sercutrity + Redis + mysql 實現分佈式項目的單點認證和鑑權

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章