springcloud的一站式解决方案,包含了丰富的组件
组件:
- 服务注册与发现
- 服务限流与降级
- 分布式配置(动态配置)
- 消息驱动
- 分布式事务
- 对象存储
- 分布式任务调度
- 短信
二.开始使用
1.nacos 注册中心
a.nacos-discover 注册发现
- 增加依赖
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
${spring.cloud.alibaba.version}
- 开启注册发现配置
在启动类上添加
@EnableDiscoveryClient
- 配置文件中配置nacos注册中心的地址
spring:
application:
name: blog-article # 配置服务的名称 不可以重复
cloud:
nacos:
discovery:
server-addr: http://121.199.20.51:8848/ #配置服务发现的nacos的地址
b.Feigen 客户端
简介:伪http客户端
使用:
- 增加依赖
org.springframework.cloud
spring-cloud-starter-openfeign
2.1.2.RELEASE
- 启动类开启注解 @EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class BlogArticleApplication {
public static void main(String[] args) {
SpringApplication.run(BlogArticleApplication.class,args);
}
}
- 使用注解 @FeignClient 声明接口
@FeignClient value指定要调用的服务
然后在接口方法上指定访问路径
@FeignClient("blog-user")
public interface UserService {
@PostMapping("login")
String login(User user);
}
c.nacos config
- 引入依赖
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
- 定义nacos-config配置文件 bootstrap.properties
注意:springboot配置文件的加载顺序
bootstrap.properties>bootstrap.yml>application.properties>application.yml
经过测试,最好nacos-config的配置文件还是使用 bootstrap.properties编写,避免出现优先级问题
spring.application.name=blog-article-config //对应nacos中的配置的dataId
spring.cloud.nacos.config.server-addr=121.199.20.51:8848 //nacos地址
spring.cloud.nacos.config.file-extension=yaml //nacos中动态配置使用的是什么后缀名
- 使用注解@ReferenceScope开启动态刷新功能,当在nacos中修改了配置后,会自动刷新
- 多环境配置(以生产环境为例)
- 建立bootstrap-prod.properties
增加spring.profiles.active属性 执行要配置的环境
spring.profiles.active=prod
spring.application.name=blog-article-config
spring.cloud.nacos.config.server-addr=121.199.20.51:8848
spring.cloud.nacos.config.file-extension=yaml
- 在nacos新建 data-id为blog-article-config-prod.yaml配置\
- 启动时指定启动配置为prod
idea中修改启动参数 Active profiles
java -jar **.jar -spring.profiles.active=prod
2.sentinel 熔断器
客户端部署
https://github.com/alibaba/Sentinel/releases/download/1.7.0/sentinel-dashboard-1.7.0.jar 下载jar包
运行命令
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
客户端接入
- 引入jar包
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
- 在配置文件中开启配置
关键配置
spring:
application:
name: blog-article
cloud:
nacos:
discovery:
server-addr: http://121.199.20.51:8848/
sentinel:
transport:
dashboard: 121.199.20.51:8180 //配置sentinel控制台
server:
port: 8090
feign:
sentinel:
enabled: true //开启feign对sentinel的支持
test:
name: hello
- 开启feign对sentinel的支持
- 配置sentinel的控制台
- 编写fallback熔断器类
注意事项:
package com.zy.blog.article.service.Fallback;
import com.zy.blog.article.service.UserService;
import com.zy.blog.domain.User;
import org.springframework.stereotype.Component;
/**
* @author: zhangyao
* @create:2019-11-27 10:23
**/
@Component
public class UserServiceFallback implements UserService {
@Override
public String login(User user) {
return "网络有问题";
}
}
- 需放入spring容器
- 实现要熔断的接口
- 在接口类上@FeignClient 指定熔断类
@FeignClient(value = "blog-user",fallback = UserServiceFallback.class)
@FeignClient(value = "blog-user",fallback = UserServiceFallback.class)
//指定容段类
public interface UserService {
@PostMapping("login")
String login(@RequestBody User user);
}
3.dubbo实现序列化(高性能)
使用kryo实现序列化更快,体积更小
- 引入依赖
注意是dubbo的,不是kryo官方的包
org.apache.dubbo
dubbo-serialization-kryo
- 配置
dubbo:
protocol:
serialization: kryo
3.Spring-Security oAuth2
1.oAuth2是什么
oAuth2 是协议
实现: Spring Security, Apache Shiro
2.为什么使用oAuth2
当第三方应用需要获取用户在资源时,必须获取用户的授权,但是为了直接把用户的用户名和密码提供给第三方应用是不安全的,这样可能用户在某一个应用的用户名密码一旦泄露,用户位于所有应用的信息都会收到威胁,所有oAuth就是为了解决这样的业务场景的一种协议.
官方解释:
An open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications.
意思是:
一个开放的协议,允许安全的授权在一个简单和标准的方法从网络,移动和桌面应用程序。
使用oAuth2协议,第三方应用申请用户授权不涉及用户的用户名密码,而是改为用户的授权模式,拿到用户的授权后,再去获取用户的资源信息.
3.怎么使用oAuth2
- Spring-Security 的四种模式
- 简化模式
- 客户端模式
- 密码模式
- 授权码模式
4.授权码模式使用
内存使用
1.引入依赖
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.2.1.RELEASE
com.zy
user-security-server
1.0-SNAPSHOT
Apache 2.0
https://www.apache.org/licenses/LICENSE-2.0.txt
zhangyao
zhangyao
zy963613606@aliyun.com
1.8
${java.version}
${java.version}
UTF-8
UTF-8
org.springframework.cloud
spring-cloud-dependencies
Finchley.SR1
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.1.0.RELEASE
org.springframework.cloud
spring-cloud-starter-oauth2
2.2.0.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
2.1.0.RELEASE
使用的是spring-cloud的oauth2 jar包 需要依赖spring-cloud
2.配置认证服务器(JavaConfig)
a.新建WebSecutiryConfiguration 配置类 继承 WebSecurityConfigurerAdapter
package com.zy.userSecurityServer.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @author: zhangyao
* @create:2019-12-05 10:13
**/
@Configuration
//启用Security安全注解
@EnableGlobalMethodSecurity(jsr250Enabled = true,prePostEnabled = true,securedEnabled = true)
public class WebSecutiryConfiguration extends WebSecurityConfigurerAdapter {
/**
* 注入默认加密类
* @return
*/
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* 在内存中创建用户
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password(passwordEncoder().encode("123456")).roles("user")
.and()
.withUser("admin").password(passwordEncoder().encode("admin")).roles("admin");
}
}
b.创建认证服务类
package com.zy.userSecurityServer.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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;
/**
* @author: zhangyao
* @create:2019-12-05 10:20
**/
//认证服务器注解
@EnableAuthorizationServer
@Configuration
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
BCryptPasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
//配置clientId
.withClient("client1")
//配置secret
.secret(passwordEncoder.encode("secret"))
//配置授权范围
.scopes("app")
//配置授权方式
.authorizedGrantTypes("authorization_code")
//回调地址
.redirectUris("http://www.baidu.com");
}
}
测试访问路径
获取授权码code:
- client_id:客户端id(必需)
- response_type:返回授权码
- redirect_uri:重定向路径 如果配置了redirect_uri就不需要在路径里继续配置了
使用授权码获取token:
http://client1:123456@localhost:8090/oauth/token
注意这里的client1:123456 对应的是你授权的客户端和密码
参数:
- code: 授权码
- grant_type: authorization_code 授权码方式
与数据库交互(Mysql为例)
1.建表
/*
Navicat Premium Data Transfer
Source Server : RDS
Source Server Type : MySQL
Source Server Version : 50725
Source Host : rm-bp1u2h6esm9zyp3y5ho.mysql.rds.aliyuncs.com:3306
Source Schema : oauth2
Target Server Type : MySQL
Target Server Version : 50725
File Encoding : 65001
Date: 09/12/2019 14:49:15
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for clientdetails
-- ----------------------------
DROP TABLE IF EXISTS `clientdetails`;
CREATE TABLE `clientdetails` (
`appId` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`resourceIds` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`appSecret` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`scope` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`grantTypes` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`redirectUrl` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`authorities` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`access_token_validity` int(11) NULL DEFAULT NULL,
`refresh_token_validity` int(11) NULL DEFAULT NULL,
`additionalInformation` varchar(4096) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`autoApproveScopes` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`appId`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for oauth_access_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_access_token`;
CREATE TABLE `oauth_access_token` (
`token_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`token` blob NULL,
`authentication_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`user_name` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`client_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`authentication` blob NULL,
`refresh_token` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`authentication_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for oauth_approvals
-- ----------------------------
DROP TABLE IF EXISTS `oauth_approvals`;
CREATE TABLE `oauth_approvals` (
`userId` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`clientId` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`scope` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`status` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`expiresAt` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0),
`lastModifiedAt` timestamp(0) NOT NULL
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for oauth_client_details
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`resource_ids` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`client_secret` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`scope` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`authorized_grant_types` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`web_server_redirect_uri` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`authorities` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`access_token_validity` int(11) NULL DEFAULT NULL,
`refresh_token_validity` int(11) NULL DEFAULT NULL,
`additional_information` varchar(4096) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`autoapprove` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`client_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for oauth_client_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_token`;
CREATE TABLE `oauth_client_token` (
`token_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`token` blob NULL,
`authentication_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`user_name` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`client_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`authentication_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for oauth_code
-- ----------------------------
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
`code` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`authentication` blob NULL
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for oauth_refresh_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_refresh_token`;
CREATE TABLE `oauth_refresh_token` (
`token_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`token` blob NULL,
`authentication` blob NULL
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
2.修改内存使用的认证服务器类
package com.zy.userSecurityServer.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import javax.sql.DataSource;
/**
* @author: zhangyao
* @create:2019-12-05 10:20
**/
//认证服务器
@EnableAuthorizationServer
@Configuration
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
/**
* 注入加密类
*/
@Autowired
BCryptPasswordEncoder passwordEncoder;
/**
* 配置数据源 使用hikaricp数据源
* @return
*/
@Bean
@Primary
@ConfigurationProperties("spring.datasource.hikari")
public DataSource dataSource(){
return DataSourceBuilder.create().build();
}
/**
* 使用JdbcTokenStore 把令牌存入Mysql数据库
* @return
*/
@Bean
public TokenStore tokenStore(){
return new JdbcTokenStore(dataSource());
}
/**
* 使用JdbcClientDetailsService 操作 clientDetails
* @return
*/
@Bean
public ClientDetailsService jdbcClientDetailsService(){
return new JdbcClientDetailsService(dataSource());
}
/**
* 配置认证服务使用的tokenService
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore());
}
/**
* 配置使用的clientDetailsService
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// clients.inMemory()
// .withClient("client1")
// .secret(passwordEncoder.encode("secret"))
// .scopes("app")
// .authorizedGrantTypes("authorization_code")
// .redirectUris("http://www.baidu.com");
clients.withClientDetails(jdbcClientDetailsService());
}
}
3.修改数据库 配置客户端id,密码,重定向路径,作用域
INSERT INTO `oauth2`.`oauth_client_details`(`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`) VALUES ('client1', NULL, '$2a$10$U/F6aI66euuFLqXP7sf6wuY4ogJ.sGQ1fyfaozD483jmvqC94m6Jq', 'app', 'authorization_code', 'https://www.baidu.com', NULL, NULL, NULL, NULL, NULL);
4.说明
此时登陆用户使用的还是内存中建立的用户,但是认证服务使用的数据库中的客户端
测试访问路径与内存一致
5.RBAC 角色控制
操作: 由在内存中创建的用户并赋予角色 ===> 在数据库中配置用户角色
修改上述内存使用中的WebSecutiryConfiguration 类
package com.zy.userSecurityServer.configuration;
import com.zy.userSecurityServer.service.impl.UserDetailServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @author: zhangyao
* @create:2019-12-05 10:13
**/
@Configuration
//启用Security安全注解
@EnableGlobalMethodSecurity(jsr250Enabled = true,prePostEnabled = true,securedEnabled = true)
public class WebSecutiryConfiguration extends WebSecurityConfigurerAdapter {
/**
* 注入默认加密类
* @return
*/
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* 注入自定义的UserDetailsService
* 也就是数据库中的用户角色匹配
* @return
*/
@Bean
@Override
public UserDetailsService userDetailsService(){
return new UserDetailServiceImpl();
}
/**
* 使用自定义的userDetailsService类
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.inMemoryAuthentication()
// .withUser("user").password(passwordEncoder().encode("123456")).roles("user")
// .and()
// .withUser("admin").password(passwordEncoder().encode("123456")).roles("admin");
auth.userDetailsService(userDetailsService());
}
}
若有收获,就点个赞吧