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;

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