微服务场景实战:基于SpringCloud Alibaba从零搭建鉴权中心服务

【SA-Token】授权 鉴权中心微服务 简而言之,BFF就是设计后端微服务API接口时,考虑到不同设备的需求,为不同的设备提供不同的API接口。有了BFF层之后,客户端只需要发起一次HTTP请求,BFF层就能调用不同的服务,然后把汇总后的数据返回给客户端,这样就减少了外网的HTTP请求,响应速度也就更快。客户端不是直接访问服务器的公共接口,而是调用BFF层提供的接口,BFF层再调用基础的服务,不同的客户端拥有不同的BFF层,它们定制客户端需要的API接口。​ 3.Payload kv形式的数据 即你想传递的数据 (授权的话就是token 信息) 阅读详情

鉴权中心服务

认识JWT

json web token 是一个开放的标准 ,它定义了一个种紧凑的,自包含的方式,用于作为json对象在各方之间安全的传输信息

  • 服务器鉴权完成之后 会生成 json 对象 发送给客户端,之后客户端和服务端传输数据都需要带上这个对象,服务器完全通过这个json对象认定客户端身份,为了防止篡改数据,服务端在生成的时候都会加上签名(加密的意思),服务器不保存session数据也就是无状态,更适合实现扩展
  • 那些环境可以考虑使用jwt呢? 用户授权 ,信息交换
JWT组成部分

Header :头部信息

Header 由两部分组成(Token类型,加密算法的名称),并且使用的是base64的编码

Payload: 我们想要传递的数据

Payload KV形式的诗数据 ,这里就是我们想要传递的信息(授权的话就是Token信息)

Signature :签名

Signature 为了得到签名 首先我们得有编码过的Header 编码过的payload 和一个密钥。签名用的算法就是header中指定的那个,之后就会对他们签名

我们需要一个签名公式

HMACSHA245(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)

产生一个签名,返回一个字符串,返回给客户端,之后客户端每次访问都要带上这个字符串,进行鉴权

JWT使用 . 号来连接 HHH.PPPP.SSSS

授权,鉴权设计

这里我们先不考虑 gateway 网关,后续会搭建,我们的重点放在中间和右边部分

鉴权部分,我们独立实现公共的工具类,为什么?以下三点

  1. JWT本质上是通过算法算出的加密字符串,也可以通过算法反向解析出来,他不依赖任何的框架,所以这个功能有可以单独提取出来的前提
  2. 我们的电商系统包含多个微服务,很显然我们每个服务都需要鉴权,于是我们把这个方法提取出来,方便复用
  3. 高性能鉴权,为什么不在授权中心做鉴权,首先他回头过http请求等一系列操作,我们在本地只用java的话 少去了很多步骤,性能得到倍数的增长
授权编码实现

我们创建新的一个服务来编写我们的鉴权中心

e-commerce-authority-center

导入相关的依赖

    <dependencies>
        <!-- spring cloud alibaba nacos discovery 依赖 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>
        <!-- Java Persistence API, ORM 规范 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- MySQL 驱动, 注意, 这个需要与 MySQL 版本对应 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.12</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.hyc.ecommerce</groupId>
            <artifactId>e-commerce-mvc-config</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- zipkin = spring-cloud-starter-sleuth + spring-cloud-sleuth-zipkin-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
            <version>2.5.0.RELEASE</version>
        </dependency>
        <!-- screw 生成数据库文档 -->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.30</version>
        </dependency>
        <dependency>
            <groupId>cn.smallbun.screw</groupId>
            <artifactId>screw-core</artifactId>
            <version>1.0.3</version>
        </dependency>
    </dependencies>

导入好依赖之后我们 编写对应的配置,如注册到naocs 加入adminserver的监管,配置数据源等 这里我们使用jpa 来做orm

配置编写

server:
  port: 7000
  servlet:
    context-path: /ecommerce-authority-center

spring:
  application:
    name: e-commerce-authority-center
  cloud:
    nacos:
      discovery:
        enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可
        server-addr: 127.0.0.1:8848 # Nacos 服务器地址
        # server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850 # Nacos 服务器地址
        namespace: 1bc13fd5-843b-4ac0-aa55-695c25bc0ac6
        metadata:
          management:
            context-path: ${server.servlet.context-path}/actuator
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: none
    properties:
      hibernate.show_sql: true
      hibernate.format_sql: true
    open-in-view: false
  datasource:
    # 数据源
    url: jdbc:mysql://127.0.0.1:3306/imooc_e_commerce?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
    username: root
    password: root
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    # 连接池
    hikari:
      maximum-pool-size: 8
      minimum-idle: 4
      idle-timeout: 30000
      connection-timeout: 30000
      max-lifetime: 45000
      auto-commit: true
      pool-name: ImoocEcommerceHikariCP
  kafka:
    bootstrap-servers: 127.0.0.1:9092
    producer:
      retries: 3
    consumer:
      auto-offset-reset: latest
  zipkin:
    sender:
      type: kafka # 默认是 web
    base-url: http://127.0.0.1:9411/

# 暴露端点
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always

配置完成之后,编写主启动类 @EnableJpaAuditing因为我们用到 自动加入创建时间和修改时间,所以我们需要打开 jpa的自动审计功能,不然会报错

@EnableJpaAuditing //允许 jpa 的自动审计
@SpringBootApplication
@EnableDiscoveryClient
public class AuthorityApplication {
    public static void main(String[] args) {
        SpringApplication.run(AuthorityApplication.class, args);

    }
}

test包下就测试环境是否正确

/**
 * 授权中心测试入口
 * 验证授权中心 环境可用性
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class AuthorityCenterApplicationTest {

    @Test
    public void conetextLoad() {

    }
}

环境ok之后

我们去测试 数据库操作是否可用

编写实体类ecommerceUser

/*
 * 用户表实体类定义
 * */
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(name = "t_ecommerce_user")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EcommerceUser {
    /* 自增组件*/
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private long id;

    /*用户名*/
    @Column(name = "username", nullable = false)

    private String username;

    /* MD5 密码*/
    @Column(name = "password", nullable = false)
    private String password;

    /*额外的信息 json 字符串存储*/
    @Column(name = "extra_info", nullable = false)
    private String extraInfo;

    /*自动加入创建时间 需要主启动类的注解*/
    @CreatedDate
    @Column(name = "create_time", nullable = false)
    private Date createTime;

    /*自动加入更新时间 需要主启动类的注解*/
    @CreatedDate
    @Column(name = "update_time", nullable = false)
    private Date updateTime;
}

有了实体类我们需要有数据操作的实现 于是编写Dao 接口

其实当我们创建接口的时候jpa就已经有了对应的基础增删改查的方法

这里我们实现两个自定义查询方法

/**
 * EcommerceUserDao 接口定义
 */
public interface EcommerceUserDao extends JpaRepository<EcommerceUser, Long> {

    /*
     * 根据用户名查询 EcommerceUser 对象
     * 等于 select * form t_ecommerce_user where username=?
     * */
    EcommerceUser findByUsername(String name);

    /*
     * 根据用户名查询 EcommerceUser 对象
     * 等于 select * form t_ecommerce_user where username=? and password=?
     * */
    EcommerceUser findByUsernameAndPassword(String name, String password);

}

之后创建 test service

/**
 * @author : 冷环渊
 * @date : 2021/12/4
 * @context: EcommerceUser 相关测试
 * @params :  null
 * @return :  * @return : null
 */
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class EcommerUserTest {
    @Autowired
    EcommerceUserDao ecommerceUserDao;

    /*测试  新增一个用户数据 */
    @Test
    public void createUserRecord() {
        EcommerceUser ecommerceUser = new EcommerceUser();
        //设置要插入的信息
        ecommerceUser.setUsername("hyc@qq.com");
        ecommerceUser.setPassword(MD5.create().digestHex("123456"));
        ecommerceUser.setExtraInfo("{}");
        //日志打印返回结果
        log.info("server user:[{}]", JSON.toJSON(ecommerceUserDao.save(ecommerceUser)));
    }

    /*测试 我们编写的自定义方法 查询 刚才创建的新角色*/
    @Test
    public void SelectUserInfo() {
        String username = "hyc@qq.com";
        log.info("select userinof:[{}]", JSON.toJSON(ecommerceUserDao.findByUsername(username)));
    }
}

测试相关的 方法 新增用户啊 或者是 按条件查询用户 ,测试均通过

生成RSA256的公钥 和 私钥 非对称加密算法

他通过 私钥加密 公钥解密来完成验证,目前很多的鉴权 都是 JWTRSA256的算法来加密鉴权的,如果了解不多,就是用RSA256就可以了

编码

编写生成公钥密钥的测试类,创建 一些我们常用的VO对象 用来储存我们常用的一些变量,比如用户信息,公钥,密钥,一些常用的属性 放进 VO的模型里

@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
/**
 *
 * @author : 冷环渊
 * @date : 2021/12/5
 * @context: RSA 非对称 加密算法
 * @params :  null 
 * @return :  * @return : null
 */
public class RSATest {
    @Test
    public void generateKeyBytes() throws Exception {
        /*获取到 RSA算法实例*/
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        /* 这里最小是 2048 低于的话 是会报错的*/
        keyPairGenerator.initialize(2048);
        /*
         * 生成公钥对
         * */
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        /*获取 公钥和私钥对象*/
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        log.info("private key:[{}]", Base64.encode(privateKey.getEncoded()));
        log.info("public key:[{}]", Base64.encode(publicKey.getEncoded()));
    }
}

创建VO对象保存 我们常用且不会变化的值和对象

存储私钥 应为是私钥 所以只对鉴权中心 暴露 于是我们在鉴权服务中创建Constant包创建这个AuthotityConstant类保存信息

/**
 * @author : 冷环渊
 * @date : 2021/12/5
 * @context: 鉴权的常量
 * @params :  null
 * @return :  * @return : null
 */
public class AuthorCanstant {
    /*私钥 只暴露给 鉴权中心 不暴露给任何的其他服务*/
    public static final String PRIVATE_KEY = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBA" +
            "QCMXrQCudalKHJlH16YHr9mI5/xyYnkp5u2gAbMFf2xAHAyykYmixJP3CqG2a8tUwiJjjTIJXP+79Jzgjgg" +
            "VbBaTakrvjeFXz9HNP1D4XD6Li+sRVjnN1iBUwIFRxiFN2EOJflA9bqeQLAge/LgAu06y3jdLLleJF7yDRuMH" +
            "YedqPl9AJa5RdJmt0OgCoVOqacB7oGkFCFISm0Cwjfgq06nyiiULGZNVt8uhDxZAE4Pi2lmf3yggXCBH9AtU/2" +
            "XdyxU9caQJOAbYGxd/mART/NivBjSqo60wcBnktI+booUbDKRBbWRxvfYqKWEwPOwxlJUB3l3pcLZm866Xl3qtVM" +
            "XAgMBAAECggEADCGjLRkik+OK/3JWmo8Nu6YYjKz+XeSecIdgDwNXiZSgHcOdjHc4fe5pPn5RxXkHo9vGdAXIoJ/Z" +
            "cGIwt5qwQx2zITSvV7eDoIPT36n8OaMEO79Cj7kYzRR/eDVMyTagDLj7ccHK/yJYFnaf5vxZxFsRdwwGeTxreD" +
            "/pwZJLxjRSz1W57v5yUJNPPimNB229EogNYHIhQ8+Z7OGiilbtBIL9r6lqlz2hUAVBzXl4kOXFVI+vEodLuV2" +
            "rtQXXrpO1+AgH5lZJ7ahShKbqHt/Q6uJSTKAhbsfv/iadcPjmYp2F7nnYBLf66Jln6AWUwnXrJ7XETOf/+Qcib" +
            "q/5m6RjAQKBgQDruxn+kaDr5uYQMVSHog+CBRBJghJ4JklhY7ZDYJ2wN2KNHOd3mW/wUVDihVIyRFniIzsWU" +
            "0lnI+4OLqNLAZOBaQB5VrjyH4fxn5b26t0xLO1d5EWcOYI8ZRhwWDWaZipe2dUMeqVVMYFeDdTdNsyGrf8x" +
            "L+OVyRDiH4s4pBIs7QKBgQCYcIVFgDbrmwsP7lA9/dU9kClutY3gjEUgB2IJp2Y8S4Xhfi4NC8GqRQoMUyuqg" +
            "vPHKEiTCa1EojGHS/+r4JVcSg9Wsv64SpGZ+gANxRhfYFPrbkjU4YOMaZeCGUfKR2QnD20c3I4gdQ9kU5nK52n+Y" +
            "JEkAFUejg1Mhb6Fp6HDkwKBgAHYYBa3CxxtnUVpLXE2Woq5AWyh4QUhv5dMkYOrgPB9Ln9OR52PDOpDqK9tP" +
            "bx4/n8fqXm+QyfUhyuDP/H5XC86JC/O9vmmN4kzp5ndMsgMwvrmK4lShet1GyDd/+VqgVBmwh0r5JlrHske" +
            "sJjesfEn8YRwDIcCoOg0OQHDfwTtAoGAQfE61YvXNihFqsiOkaKCYjVAlxGWpDJJnMdU05REl4ScD6WDy" +
            "kTxq/RdmmNIGmS3i8mTS3f+Khh3kG2B1ho6wkePRxP7OEGZpqAM8ef22RtUch2tB9neDBmJXtAMzCYB3xu/O" +
            "aL3IHdDB0Va2/krUsz3PDmgmK0ed6HLfwm64l0CgYB+iGkMAQEwqYmcCEXKK825Q9y/u8PE9y8uaMGfsZQzDo6v" +
            "V5v+reOhmZRrk5BnX+pgztbE28sS6c2vYR0RYoR90aD2GXungCPXWEMDQudHFxvSsNTCYkDynjTSlnzu9aDcfqw1" +
            "UIzHog2zCquSro7tnbOMsvV5UdsLBq+WNQGgAw==";

    /*默认的 token 超时时间,一天*/
    public static final Integer DEFAULT_EXPIRE_DAY = 1;
}

之后是创建一些公共常用的VO模型 e-commerce-common

保存 公钥到公用包 以后我们的服务 需要做授权都需要使用到

/**
 * @author : 冷环渊
 * @date : 2021/12/5
 * @context: 通用模块的常量定义
 * @params :  null
 * @return :  * @return : null
 */
public class CommonCanstant {
    /* RSA 公钥*/
    public static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjF60ArnWpShyZ" +
            "R9emB6/ZiOf8cmJ5KebtoAGzBX9sQBwMspGJosST9wqhtmvLVMIiY40yCVz/u/Sc4I4IFWwWk2pK743hV8/RzT9Q+F" +
            "w+i4vrEVY5zdYgVMCBUcYhTdhDiX5QPW6nkCwIHvy4ALtOst43Sy5XiRe8g0bjB2Hnaj5fQCWuUXSZrdDoAqFTqmnA" +
            "e6BpBQhSEptAsI34KtOp8oolCxmTVbfLoQ8WQBOD4tpZn98oIFwgR/QLVP9l3csVPXGkCTgG2BsXf5gEU/zYrwY0qqO" +
            "tMHAZ5LSPm6KFGwykQW1kcb32KilhMDzsMZSVAd5d6XC2ZvOul5d6rVTFwIDAQAB";

    /* JWT 中 存储用户信息到 key*/
    public static final String JWT_USER_INFO_KEY = "e-commerce-user";
    /*授权中心的 service-id*/
    public static final String AUTHORITY_CENTER_SERVICE_ID = "e-commerce-authity-center";
}

用户信息的常用VO对象

  • JwtToken
  • LoginUserinfo
  • UsernameAndPassword
/**
 * @author : 冷环渊
 * @date : 2021/12/5
 * @context: 授权中心 鉴权 之后给客户端的token
 * @params :  null
 * @return :  * @return : null
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class JwtToken {
    /* JWT*/
    private String token;


}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginUserinfo {
    /*用户 id*/
    private Long id;
    /*用户名*/
    private String username;
}

/**
 * @author : 冷环渊
 * @date : 2021/12/5
 * @context:用户名和密码
 * @params :  null
 * @return :  * @return : null
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UsernameAndPassword {
    /*用户名 */
    private String username;
    /*密码*/
    private String password;
}

授权服务编写

首先创建一个 接口 IJWTService

定义我们需要实现的授权方法

/**
 * @author : 冷环渊
 * @date : 2021/12/5
 * @context: JWT 相关服务接口定义
 * @params :  null
 * @return :  * @return : null
 */
public interface IJWTService {

    /*
     * 生成 token 使用默认的超时时间
     * */
    String generateToken(String username, String password) throws Exception;

    /*
     * 生成 JWT Token 可以设置超时时间 单位是天
     * */
    String generateToken(String username, String password, Integer expireTime) throws Exception;


    /*
     * 注册用户并且生成 token 返回
     * */
    String registerUserAndGenerateToken(UsernameAndPassword usernameAndPassword) throws Exception;
}

授权方法实现类

这里我们有三个方法实现

  • 默认超时时间的 生成 token
  • 自定义超时时间的设置生成token
  • 注册新用户并且生成的token返回

JWT对象生成细节:

1) 我们需要设置需要传递的对象

2)我们需要设置一个不重复的 id

3)我们需要设置超时时间

4)设置我们的加密签名

5)完成设置返回字符串对象

Jwts.builder()
                //这里 claim 其实就是 jwt 的 payload 对象 --> KV
                .claim(CommonCanstant.JWT_USER_INFO_KEY, JSON.toJSONString(loginUserinfo))
                // jwt id 表示是 jwt的id
                .setId(UUID.randomUUID().toString())
                //jwt 的过期时间
                .setExpiration(expireDate)
                // 这里是设置加密的私钥和加密类型
                .signWith(getPrivateKey(), SignatureAlgorithm.RS256)
                //生成 jwt信息 返回的是一个字符串类型
                .compact();
    }

完整代码

@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class IJWTServiceIpml implements IJWTService {

    @Autowired
    private EcommerceUserDao ecommerceUserDao;

    @Override

    public String generateToken(String username, String password) throws Exception {
        return generateToken(username, password, 0);
    }

    @Override
    public String generateToken(String username, String password, Integer expireTime) throws Exception {
        //首先需要验证用户是否通过授权校验,即 输入的用户名和密码能否寻找到匹配数据表的记录
        EcommerceUser ecommerceUser = ecommerceUserDao.findByUsernameAndPassword(username, password);
        if (ecommerceUser == null) {
            log.error("can not find user:[{}],[{}]", username, password);
            return null;
        }

        //Token 中塞入对象, 即 JWT中 储存的对象,后端拿到这些信息 就可以知道那个用户在操作
        LoginUserinfo loginUserinfo = new LoginUserinfo(
                ecommerceUser.getId(), ecommerceUser.getUsername()
        );

        if (expireTime <= 0) {
            expireTime = AuthorCanstant.DEFAULT_EXPIRE_DAY;
        }
        //计算超时时间
        ZonedDateTime zdt = LocalDate.now().plus(expireTime, ChronoUnit.DAYS)
                .atStartOfDay(ZoneId.systemDefault());
        Date expireDate = Date.from(zdt.toInstant());

        return Jwts.builder()
                //这里 claim 其实就是 jwt 的 payload 对象 --> KV
                .claim(CommonCanstant.JWT_USER_INFO_KEY, JSON.toJSONString(loginUserinfo))
                // jwt id 表示是 jwt的id
                .setId(UUID.randomUUID().toString())
                //jwt 的过期时间
                .setExpiration(expireDate)
                // 这里是设置加密的私钥和加密类型
                .signWith(getPrivateKey(), SignatureAlgorithm.RS256)
                //生成 jwt信息 返回的是一个字符串类型
                .compact();
    }

    @Override
    public String registerUserAndGenerateToken(UsernameAndPassword usernameAndPassword) throws Exception {
        //先去校验 用户名是否存在 如果存在 不能重复注册
        EcommerceUser oldUser = ecommerceUserDao.findByUsername(usernameAndPassword.getUsername());
        if (null != oldUser) {
            log.error("username is registered:[{}]", oldUser.getUsername());
            return null;
        }
        EcommerceUser ecommerceUser = new EcommerceUser();
        ecommerceUser.setUsername(usernameAndPassword.getUsername());
        ecommerceUser.setPassword(usernameAndPassword.getPassword()); //MD5 编码以后
        ecommerceUser.setExtraInfo("{}");

        //注册一个新用户 写到一个 记录表中
        ecommerceUser = ecommerceUserDao.save(ecommerceUser);

        log.info("regiter user success:[{}],[{}]", ecommerceUser.getUsername());

        //生成 token 并且返回
        return generateToken(ecommerceUser.getUsername(), ecommerceUser.getPassword());
    }

    /*
     * 根据本地储存的私钥获取到 PrivateKey对象
     * */
    private PrivateKey getPrivateKey() throws Exception {

        //使用给定的编码密钥创建一个新的PKCS8EncodedKeySpec。
        PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(new BASE64Decoder().decodeBuffer(AuthorCanstant.PRIVATE_KEY));
        // 设置生成新密钥的工厂加密方式
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        //返回生成好的密钥
        return keyFactory.generatePrivate(priPKCS8);
    }
}

之后我们的授权都会使用到以上的方法

Controller

我们需要给注册用户和生成token 一个程序的入口

就是我们的 AuthorityController,这里可以用到我们之前使用的注解@IgnoreResponseAdvice我们为啥那么不让他封装呢,我们需要验证,单纯的 JwtToken对象就可以了,不需要封装和转化

@Slf4j
@RestController
@RequestMapping("/authority")
public class AuthorityConroller {
    private final IJWTService ljwtService;

    public AuthorityConroller(IJWTService ljwtService) {
        this.ljwtService = ljwtService;
    }

    /*
     * 从授权中心 获取 token (其实就是登陆功能) 且返回信息中没有统一响应的包装
     * */
    @IgnoreResponseAdvice
    @PostMapping("/token")
    public JwtToken token(@RequestBody UsernameAndPassword usernameAndPassword) throws Exception {
        //通常 日志里不会答打印用户的信息 防止泄露,我们这本身就是一个授权服务器,本身就不对外开放,所以我们可以打印用户信息到日志方便查看
        log.info("request to get token with param:[{}]", JSON.toJSONString(usernameAndPassword));
        return new JwtToken(ljwtService.generateToken(
                usernameAndPassword.getUsername(),
                usernameAndPassword.getPassword()));
    }

    /*注册用户并且返回注册当前用户的token 就是通过授权中心常见用户*/
    @IgnoreResponseAdvice
    @PostMapping("/register")
    public JwtToken register(@RequestBody UsernameAndPassword usernameAndPassword) throws Exception {
        log.info("register user with param:[{}]", JSON.toJSONString(usernameAndPassword));
        return new JwtToken(ljwtService.registerUserAndGenerateToken(usernameAndPassword));
    }
}
鉴权编码实现

这里我们打鉴权 放到公共模块里 为什么呢,这里我们不止是鉴权中心还有其他的服务也要用到鉴权服务,秉着封装的思想,我们提取公共的方法放到 Common里面

创建JWT Token解析类TokenParseUtil

/**
 * @author : 冷环渊
 * @date : 2021/12/5
 * @context: JWT Token 解析工具类
 * @params :  null
 * @return :  * @return : null
 */
public class TokenParseUtil {

    public static LoginUserinfo parseUserInfoFromToken(String token) throws Exception {
        if (null == token) {
            return null;
        }
        Jws<Claims> claimsJws = parseToken(token, getPublicKey());
        Claims body = claimsJws.getBody();
        //如果 Token 已经过期返回 null
        if (body.getExpiration().before(Calendar.getInstance().getTime())) {
            return null;
        }
        //     返回 Token中保存的用户信息
        return JSON.parseObject(
                body.get(CommonCanstant.JWT_USER_INFO_KEY).toString(), LoginUserinfo.class
        );
    }

    /*
     * 通过公钥去解析 JWT Token
     * */
    private static Jws<Claims> parseToken(String token, PublicKey publicKey) {
        // 用设置签名公钥,解析claims信息 token
        return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
    }

    /*
     * 根据本地存储的公钥获取到 getPublicKey
     * */
    public static PublicKey getPublicKey() throws Exception {

        //解码器 我们设置解码器 将公钥放进去
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(
                new BASE64Decoder().decodeBuffer(CommonCanstant.PUBLIC_KEY)
        );
        //创建 RSA 实例 通过示例生成公钥对象
        return KeyFactory.getInstance("RSA").generatePublic(keySpec);
    }
}

这里是涉及到一个问题 ,token要是传输的不是jwt token对象,会跑出异常,没有兜底,

其实这里这问题其实也不成立,应为你没有传入token对象,我们这里抛出异常是正确的,也不会影响其他服务,之后搭配sentinel和豪猪哥 可以实现异常重启等等,这里我们就先不编写兜底方法,以解析jwt token为主。

验证鉴权授权

我们写一个 test 类来测试 授权和鉴权拿到对象,是否有效

/**
 * @author : 冷环渊
 * @date : 2021/12/5
 * @context: JWT 相关测试类
 * @params :  null
 * @return :  * @return : null
 */
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class JWTServiceTest {

    @Autowired
    private IJWTService ijwtService;

    @Test
    public void testGenerateAndParseToken() throws Exception {
        String jwtToken = ijwtService.generateToken(
                "hyc@qq.com", "e10adc3949ba59abbe56e057f20f883e"
        );
        log.info("jwt token is:[{}]", jwtToken);
        LoginUserinfo userinfo = TokenParseUtil.parseUserInfoFromToken(jwtToken);
        log.info("userinfo by jwt prase token :[{}]", JSON.toJSONString(userinfo));
    }
}

启动测试查看结果

eyJhbGciOiJSUzI1NiJ9

.eyJlLWNvbW1lcmNlLXVzZXIiOiJ7XCJpZFwiOjExLFwidXNlcm5hbWVcIjpcImh5Y0BxcS5jb21cIn0iLCJqdGkiOiIzNDgwNjdjMi00MTBlLTQ3MjItYmM3ZS02NWQyYmNmYTRkN2MiLCJleHAiOjE2Mzg3MjAwMDB9

.ZbFl81MkIipJSULZLf4F2X2Fb0q1TwhHIMT7nyZsZVwUxXyZnK54RlzoGM_b-kMUdKO_Tab-qEeOT6Jn--FiKmbOziWXiBx3a-k5ipthMJx0Fez-X8Acty-Pg7zukNalugiLxGb5ophQoVQWRTDmv2hytGHqiV71HVyErznkJa36QQr6QsjXqlJleo3BBt-6BFzdTFPLUmdTEJ4XsmZBa_acUDGBhY0_tU2gYtKBWhwvMCknuyCcV-_GVI5EvgMIKRpeFSZrWfTsDG2y1MFcyzjKE6jnzek-YwT3XkzQ8eGzUbiOlaU_Zx5OJah-UtrKwqlAw9WbO71pNgEBefdsYw

这是封装好的 JWT Token 这里我们可以看到三个点分别分割 了 header和payload以及签名,和我们之前讲的 结构一模一样,

userinfo by jwt prase token :[{"id":11,"username":"hyc@qq.com"}]

获取到的我们放在 jwt 里面需要传递的对象

验证对外提供的接口是否好用

这里我们编写 http脚本来测试对外题提供的接口是否有用

Token 方法

### 获取 Token -- 登录功能实现
POST http://127.0.0.1:7000/ecommerce-authority-center/authority/token
Content-Type: application/json

{
  "username": "hyc@qq.com",
  "password": "e10adc3949ba59abbe56e057f20f883e"
}
POST http://127.0.0.1:7000/ecommerce-authority-center/authority/token

HTTP/1.1 200 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sun, 05 Dec 2021 15:35:52 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
  "token": "eyJhbGciOiJSUzI1NiJ9.eyJlLWNvbW1lcmNlLXVzZXIiOiJ7XCJpZFwiOjExLFwidXNlcm5hbWVcIjpcImh5Y0BxcS5jb21cIn0iLCJqdGkiOiIxNDU1M2FjZi1lZmE5LTQ4OTgtOTliYS1hNzA4NWI4MjU4MzAiLCJleHAiOjE2Mzg3MjAwMDB9.AlOpo6uf97R20ZLojXeun-3MK8DpSYlWxEygvDrtQeWaM9R0iKx-iW1VXnK6WoEntvqPxIrmPA7khjl3dXPa8kQHtdq-LVO7BDuZZDiQyZ64ZS7A9jWZr5JReSWBUSR1YUnsOvBRMkx4JVcAF3_W7nHwd722FFzOZRCr72hLHQIKpsugKtqjMEtaiEW0vcqphCYRJTAO_rQx1Lb1eVVg_Ufur0qSlKkV5dSJ0x3x9mc9UZRckwN0rrP7wQxZcrxJvKTfX7CkRRSO-CxZbG4WLokSaMtaGBMWU-7KGq7HSCZ0yuOgbbLdouHncsp6VD2tNLFdWSdJ_whCIbZxfX8R7w"
}

获取 token 成功

这里他没有被响应包裹,证明我们之前的选择屏蔽注解也生效了,很符合我们的预期

验证如果记录数据表没有是否会返回null

### 获取 Token -- 登录功能实现
POST http://127.0.0.1:7000/ecommerce-authority-center/authority/token
Content-Type: application/json
### 随便写的id

{
"username": "hyc1111@qq.com",
"password": "e10adc3949ba59abbe56e057f20f883e"
}

返回结果 也符合我们预期 是 null

POST http://127.0.0.1:7000/ecommerce-authority-center/authority/token

HTTP/1.1 200 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sun, 05 Dec 2021 15:40:44 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
  "token": null
}

register

### 注册用户并返回 Token -- 注册功能实现
POST http://127.0.0.1:7000/ecommerce-authority-center/authority/register
Content-Type: application/json

{
  "username": "hyc@qq.com",
  "password": "e10adc3949ba59abbe56e057f20f883e"
}

这个用户之前是注册过的,我们来看一下是否会返回我们预期的处理

POST http://127.0.0.1:7000/ecommerce-authority-center/authority/register

HTTP/1.1 200 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sun, 05 Dec 2021 15:42:00 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
  "token": null
}

现在我们去注册一个新的用户

### 注册用户并返回 Token -- 注册功能实现
POST http://127.0.0.1:7000/ecommerce-authority-center/authority/register
Content-Type: application/json

{
  "username": "hyc11@qq.com",
  "password": "e10adc3949ba59abbe56e057f20f883e"
}

符合预期结果,创建了我们预期的对象,这个时候我们去看一下数据表

POST http://127.0.0.1:7000/ecommerce-authority-center/authority/register

HTTP/1.1 200 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sun, 05 Dec 2021 15:42:57 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
  "token": "eyJhbGciOiJSUzI1NiJ9.eyJlLWNvbW1lcmNlLXVzZXIiOiJ7XCJpZFwiOjEyLFwidXNlcm5hbWVcIjpcImh5YzExQHFxLmNvbVwifSIsImp0aSI6IjMxNDc0NmIwLTMyOGYtNDZkNS05ZTIwLTg3YjI0OWY1ZjZkOCIsImV4cCI6MTYzODcyMDAwMH0.MKxk-Q4BG5kaYFAsLiy13trtk_gDFmCKORpdE4EAwgSVecXFQcYfT1VvqSAKvoQLFsSlQAxOR5elV8CFOoKwAomwqdyyghZp63NKJ2smRbg3Y-4jWBzFVsUgcjOY2fwh7oNTdHEsWmLBYAh5r0hm_MysZsUEsE-cwb3sw8NSMk1OZp0J6tcRras7V1Uw5xXH8OnCoq2cUfdynJMHS29EzJT1TFPb8unVQ_A1RWodsHdK3n1Bl4wFbJjMtnHx7vzOeAUSNJx1XpAGdo0xYHK6HBpS9E1KBS3x1AnYFONM0DKd4-_QxMkBW1kkg2uWrRpf3GYZF20FKxXgmBAPHGZhew"
}

对象生成,功能验证一切正常

鉴权服务中心总结

对比基于Token与基于服务器的身份认证

传统:

  • 最为传统的做法,客户端储存 cookie 一般是 Session id 服务器存储 Session
  • Session 是每次用户认证通过以后 ,服务器需要创建一条记录保存用户信息,通常是在内存中(也可以放在redis中),随着认证通过的用户越来越多,服务器的在这里的开销就会越来越大
  • 不同域名之前切换的时候,请求可能会被禁止,即跨越问题

基于token

  • JWT与Session的差异相同点是,他们都是存储用户信息。然而Session是在服务器端的,而JWT是在客户端的
  • JWT方式将用户状态分散到了客户端中,可以明显减轻请服务器的内存压力,服务端只需要用算法解析客户端的token就可以得到信息

两者优缺点的对比

  • 解析方法:JWT使用算法直接解析得到用户信息;Session需要额外的数据映射。实现匹配
  • 管理方法:JWT只有过期时间的限制,Session 数据保存在服务器,可控性更强
  • 跨平台:JWT就是一段字符串,可以任意传播,Session跨平台需要有统一的解析平台,较为繁琐
  • 时效性:JWT一旦生成 独立存在,很难做到特殊的控制;Session时效性完全由服务端的逻辑说了算

TIPS :各自都有优缺点,都是登陆和授权的解决方案

微服务:gateway+security+nacos实现微服务的认证授权方案 用户通过客户端访问项目时,前端项目会部署在nginx上,加载静态文件时直接从nginx上返回即可。当用户在客户端操作时,需要调用后端的一些服务接口。这些接口会通过Gateway网关,网关进行一定的处理(jwt合法性校验,黑名单、白名单,过滤一部分请求)之后再转发给具体的微服务。具体的资源服务会对请求进行解析,判断当前登录用户是否有权限调用该资源的接口。 阅读详情

相关推荐

SpringCloud Gateway整合Sa-Token实现微服务鉴权

在微服务架构中,API网关作为系统流量的统一入口,其鉴权机制直接影响整体安全性。基于Token的无状态认证是现代分布式系统的核心方案,通过JWT或自定义Token实现服务间信任传递。Sa-Token作为轻量级Java权限框架,通过简洁的注解和API设计,显著降低了微服务鉴权的实现复杂度。该方案结合SpringCloud Gateway的过滤机制,可实现路由级鉴权拦截,配合Redis存储会话信息,既保证安全性又满足水平扩展需求。典型应用场景包括电商系统的订单鉴权、ERP系统的角色权限控制等,其中Token存储

weixin_34268169的博客 422

常见的鉴权方式简述

简述常见的鉴权方式

tangsiqi130的博客 7420

集成网关后怎么做权限隔离——统一鉴权

商场停车场景中,除了极少数功能不需要用户登陆外(如可用车位数),其余都是需要用户在会话状态下才能正常使用的功能。上个章节中提到,要在网关层实现统一的认证操作,本篇就直接带你在网关层增加一个公共鉴权功能,来实现简单的认证,采用轻量级解决方案 JWT 的方式来完成。 为什么选 JWT JSON Web Token(缩写 JWT)是比较流行的轻量级跨域认证解决方案,Tomcat 的 Session 方...

东南草堂 1678

微服务之用户鉴权中心

一、预备知识 本文讨论基于微服务架构下的身份认证和用户授权的技术方案,在阅读之前,最好先熟悉并理解以下几个知识点: 微服务架构相关概念:服务注册、服务发现、API 网关 身份认证和用户授权:SSO、CAS、OAuth2、JWT 文章在涉及到上述知识内容时,会附上参考链接。此外,还有以下几个基础概念,在身份治理领域容易混淆: 认证 授权 鉴权 权限控制 建议参考 pphh 的博文《认证、授权、鉴权和权限控制》: http://www.hyhblog.cn/2018/04/25/user_login_a

weixin_42143904的博客 3332

《项目实战》构建SpringCloud alibaba项目(一、构建父工程、公共库、网关))

本章节讲解如何构建SpringCloud alibaba项目,以父子工程形式搭建。 - 父工程规范Springboot版本、SpringCloud版本、SpringCloud alibaba版本; - 子工程包括公共方法库(公共的DTO、http统一返回类(枚举code码等)),Gateway网关(集成Sentinel)、内网微服务统一接口层、内网微服务发布方、内网微服务调用方等;

Java 技术专栏,从入门到精通,熟悉企业级开发 1万+

从Mate到Mate40 Pro+:华为旗舰核心配置演进与选购避坑指南

本文回顾了华为Mate系列从初代到Mate40 Pro+的核心配置演进历程,重点分析了处理器性能、影像系统、屏幕设计及续航快充的技术突破。针对选购需求,提供了区分版本、5G选择及存储配置的实用避坑建议,帮助消费者明智选择华为旗舰机型。

weixin_30015371的博客 494

【SpringCloud Alibaba】 介绍及微服务模块搭建

Spring Cloud Alibaba致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过Spring Cloud编程模型轻松使用这些组件来开发分布式应用服务。 依托Spring Cloud Alibaba ,只需要添加一些注解和少量配置,就可以将Spring Cloud应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。

阿Q的小窝 1万+

不用买显示器!用USBMMID虚拟显示器软件在Win10上扩展4个屏幕(保姆级教程)

本文提供了一份详细的保姆级教程,指导用户如何在Windows 10系统上,无需购买额外硬件,通过USBMMID虚拟显示器软件扩展出多达4个虚拟屏幕。文章深入解析了虚拟显示器的核心原理,并基于微软IDD框架,手把手教学从软件获取、环境检查到安装配置的全过程,帮助开发者和多任务用户构建高效、免费的虚拟多屏工作站,实现生产力的飞跃。

backprop5master的博客 659

从零搭建基于SpringCloud Alibaba 鉴权中心服务(详细教程)

json web token 是一个开放的标准 ,它定义了一个种紧凑的,自包含的方式,用于作为json对象在各方之间安全的传输信息 服务器鉴权完成之后 会生成 json 对象 发送给客户端,之后客户端和服务端传输数据都需要带上这个对象,服务器完全通过这个json对象认定客户端身份,为了防止篡改数据,服务端在生成的时候都会加上签名(加密的意思),服务器不保存session数据也就是无状态,更适合实现扩展 那些环境可以考虑使用jwt呢?用户授权 ,信息交换

2401_83384536的博客 1197

U8采购入库单CO接口开发实战:加载、新增与删除操作详解

本文详细解析了用友U8采购入库单CO接口的开发实战,重点介绍了加载、新增与删除三大核心操作的实现方法。通过C#代码示例和实际项目经验,帮助开发者高效处理采购入库单,提升企业供应链管理效率。文章还涵盖了环境配置、异常处理、性能优化等关键技巧,适合U8二次开发人员参考。

weixin_33462927的博客 375

AI硬件加速:CPU vs GPU性能对比

AI硬件加速:CPU vs GPU性能对比 关键词:人工智能、硬件加速、CPU、GPU、性能对比、硬件架构、并行计算、优化策略、项目实战 摘要: 本文将深入探讨AI

AI天才研究院 1914

从零搭建 Spring Cloud 微服务项目:注册中心 + 网关 + 配置中心全流程

本文面向具备 Java 基础与 Spring Boot 实战经验的开发者,以 Spring Cloud Alibaba 生态为核心,从零搭建包含注册中心、API 网关、配置中心的微服务项目,全程附带可运行代码与实操说明,读者可边读边动手实现。

lbbxmx111的博客 2836

Allegro如何用自带的功能将线段变成铜皮操作指导

在做PCB设计的时候,有时根据设计需要将线段变成铜皮,可以借助辅助工具来实现这一操作,但是Allegro自身也自带这个功能,如下图。勾选Delete original objects。如何用自带的功能将线段变成铜皮操作指导。勾选Convert to shape,需要把这段走线变成铜皮。

weixin_54787054的博客 2946

SpringCloud Alibaba 从入门到精通(精选)

SpringCloud Alibaba 从入门到精通 一. 课程介绍 1.1 课程导学 什么是SpringCloudAlibaba? 阿里巴巴结合自身微服务实践,开源的微服务全家桶 在Spring Cloud项目中孵化,很可能成为Spring Cloud第二代标准的实现 在业界广泛使用,已有很多成功案例 Spring Cloud Alibaba真实应用场景 大型复杂的系统,例如大型电商系统 高并发系统,例如大型门户,秒杀系统 需求不明确,且变更很快的系统,例如初创公司业务系统 Sprin

暗余的博客 3万+

YOLOv11改进策略【模型轻量化】| 替换骨干网络 CVPR-2024 StarNet,超级精简高效的轻量化模块

本文记录的是基于StarNet的YOLOv11轻量化改进方法研究。StarNet设计简洁,没有复杂的设计和精细调整的超参数,仅是一个 4 阶段的分层架构。并且其中能够在低维空间计算的同时考虑极高维的特征这一特性,进而提高模型精度。本文在替换骨干网络中配置了原论文中的starnet_s1starnet_s2starnet_s3和starnet_s4七种模型,以满足不同的需求。

Limiiiing的博客 5987

FLUENT Meshing Watertight Geometry工作流入门 - 9 生成体网格

总结一下我们学到的东西。讨论体积网格的重要性,并了解生成体积网格的不同方法。还了解体积网格质量的重要性,并学习如何改进它。

B_etter_Man的博客 1万+

从零搭建基于SpringCloud Alibaba 鉴权中心服务(保姆级教程)

json web token 是一个开放的标准 ,它定义了一个种紧凑的,自包含的方式,用于作为json对象在各方之间安全的传输信息服务器鉴权完成之后 会生成 json 对象 发送给客户端,之后客户端和服务端传输数据都需要带上这个对象,服务器完全通过这个json对象认定客户端身份,为了防止篡改数据,服务端在生成的时候都会加上签名(加密的意思),服务器不保存session数据也就是无状态,更适合实现扩展那些环境可以考虑使用jwt呢?用户授权 ,信息交换。Payload:我们想要传递的数据Payload KV形式

jjc4261的博客 1341

别让 Claude Code 一直问你“能不能执行“:权限配置完全指南

Claude Code 提供了一套精细的权限配置机制,配置好权限设置,可以提速不少。这个小技巧需要掌握一下。

沐风 3843

SpringCloud Alibaba 从零搭建鉴权中心服务(详细教程)

服务器鉴权完成之后 会生成 json 对象 发送给客户端,之后客户端和服务端传输数据都需要带上这个对象,服务器完全通过这个json对象认定客户端身份,为了防止篡改数据,服务端在生成的时候都会加上签名(加密的意思),服务器不保存session数据也就是无状态,更适合实现扩展。编写生成公钥密钥的测试类,创建 一些我们常用的VO对象 用来储存我们常用的一些变量,比如用户信息,公钥,密钥,一些常用的属性 放进 VO的模型里。然而Session是在服务器端的,而JWT是在客户端的。

竹林幽深 254

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【微服务架构】SpringCloud Alibaba(一):Nacos作为注册中心(集群搭建)

Nacos集群通常由多个Nacos Server节点组成,这些节点通过网络相互连接并协同工作。客户端与Nacos集群进行通信,获取服务列表、配置信息等。

专注上位机开发、机器视觉、机器学习、嵌入式软硬件开发 1万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

你给我解释解释,为什么TMD非得选择SpringCloud alibaba作为微服务开发框架?

什么是微服务 提到微服务不得不提Martin Fowler在2014年3月25日发表的文章 Microservices,里面给出了微服务的定义。后续国内所有关于微服务的介绍都是基于这篇文章的翻译,或加上自己的理解而成。其中最重要的一段如下: In short, the microservice architectural style [1] is an approach to developing a single application as a suite of small services, eac

飘渺Jam的博客 5502

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

alibaba微服务nacos配置中心实战。

Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持。使用 Spring Cloud Alibaba Nacos Config,您可以在 Nacos Server 集中管理你 Spring Cloud 应用的外部属性配置。Group是组织配置的维度之一。通过一个有意义的字符串对配置集进行分组,从而区分Data ID相同的配置集。当您在Nacos上创建一个配置是,如果为天蝎配置分组的名称,则配置分组的名称默认采用DEFAULT_GROUP。

weixin_42597080的博客 2173

SpringCloud Alibaba实战(7:nacos注册中心管理微服务)

SpringCloud Alibaba实战第7篇,将服务注册到搭建的Nacos Server。

三分恶的博客 1893

【微服务架构】SpringCloud Alibaba(一):Nacos作为注册中心(注册中心原理、源码解析)

Spring Cloud Alibaba是阿里巴巴提供的一站式微服务解决方案,是Spring Cloud体系中的一个重要分支,它将阿里巴巴在微服务领域的实践经验和开源技术进行了整合,为开发者提供了一系列便捷的工具和组件,用于构建分布式微服务应用。以下是其详细介绍:首先服务在启动的时候会将数据注册到注册中心,这样就服务只要启动就可以对外提供服务了, 那么同时他也要维持一个心跳,心跳的意义就是某个服务挂掉,我肯定让注册中心知道,如果服务挂了还没有告诉注册中心,

专注上位机开发、机器视觉、机器学习、嵌入式软硬件开发 1万+

【Spring Cloud Alibaba 温故而知新】(三)授权、鉴权中心微服务

文章目录目录6.1.1 JWT 目录 6.1.1 JWT JWT的基本概念 Json Web Token (JWT) 是一个开放标准,它定义了一种紧凑的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息 哪些场景下可以考虑使用 JWT? 用户授权 信息交换 JWT的结构以及含义 JWT由三个部分组成:Header、Payload、Signature,且用圆点连接 xxx.yyyy.zzzz Header:由两部分(Token类型、加密算法名称)组成,并使用 Base64 编

Eddie'Blog 439
上一篇: cloud Alibaba电商后台组件实战:Nacos2.0.3配置持久化与集群(跟着步骤走,绝对不会出错)
下一篇: Springcloud Gateway:动态配置,过滤器源码思路
冷环渊
博客等级 码龄7年 1130粉丝 176原创
评论 13
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冷环渊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值