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

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 微服务场景实战:基于SpringCloud Alibaba从零搭建鉴权中心服务(2)

编码


编写生成公钥密钥的测试类,创建 一些我们常用的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对象


/**
 * @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);
    }
}

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


相关文章
|
1月前
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo:微服务通信的高效解决方案
【10月更文挑战第15天】随着信息技术的发展,微服务架构成为企业应用开发的主流。Spring Cloud Dubbo结合了Dubbo的高性能RPC和Spring Cloud的生态系统,提供高效、稳定的微服务通信解决方案。它支持多种通信协议,具备服务注册与发现、负载均衡及容错机制,简化了服务调用的复杂性,使开发者能更专注于业务逻辑的实现。
58 2
|
28天前
|
Kubernetes 负载均衡 Docker
构建高效后端服务:微服务架构的探索与实践
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于任何在线业务的成功至关重要。本文将深入探讨微服务架构的概念、优势以及如何在实际项目中有效实施。我们将从微服务的基本理念出发,逐步解析其在提高系统可维护性、扩展性和敏捷性方面的作用。通过实际案例分析,揭示微服务架构在不同场景下的应用策略和最佳实践。无论你是后端开发新手还是经验丰富的工程师,本文都将为你提供宝贵的见解和实用的指导。
|
13天前
|
JSON Java 测试技术
SpringCloud2023实战之接口服务测试工具SpringBootTest
SpringBootTest同时集成了JUnit Jupiter、AssertJ、Hamcrest测试辅助库,使得更容易编写但愿测试代码。
46 3
|
27天前
|
监控 API 持续交付
构建高效后端服务:微服务架构的深度探索
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于支撑复杂的业务逻辑和海量数据处理至关重要。本文深入探讨了微服务架构的核心理念、实施策略以及面临的挑战,旨在为开发者提供一套构建高效、可扩展后端服务的方法论。通过案例分析,揭示微服务如何帮助企业应对快速变化的业务需求,同时保持系统的稳定性和灵活性。
46 9
|
29天前
|
监控 安全 Java
构建高效后端服务:微服务架构深度解析与最佳实践###
【10月更文挑战第19天】 在数字化转型加速的今天,企业对后端服务的响应速度、可扩展性和灵活性提出了更高要求。本文探讨了微服务架构作为解决方案,通过分析传统单体架构面临的挑战,深入剖析微服务的核心优势、关键组件及设计原则。我们将从实际案例入手,揭示成功实施微服务的策略与常见陷阱,为开发者和企业提供可操作的指导建议。本文目的是帮助读者理解如何利用微服务架构提升后端服务的整体效能,实现业务快速迭代与创新。 ###
63 2
|
1月前
|
消息中间件 Kafka 数据库
微服务架构中,如何确保服务之间的数据一致性?
微服务架构中,如何确保服务之间的数据一致性?
|
1月前
|
JSON Java 数据格式
【微服务】SpringCloud之Feign远程调用
本文介绍了使用Feign作为HTTP客户端替代RestTemplate进行远程调用的优势及具体使用方法。Feign通过声明式接口简化了HTTP请求的发送,提高了代码的可读性和维护性。文章详细描述了Feign的搭建步骤,包括引入依赖、添加注解、编写FeignClient接口和调用代码,并提供了自定义配置的示例,如修改日志级别等。
87 1
|
1月前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
|
1月前
|
运维 Kubernetes 开发者
构建高效后端服务:微服务架构与容器化技术的结合
【10月更文挑战第18天】 在数字化转型的浪潮中,企业对后端服务的要求日益提高,追求更高的效率、更强的可伸缩性和更易于维护的系统。本文将探讨微服务架构与容器化技术如何结合,以构建一个既灵活又高效的后端服务体系。通过分析当前后端服务面临的挑战,介绍微服务和容器化的基本概念,以及它们如何相互配合来优化后端服务的性能和管理。本文旨在为开发者提供一种实现后端服务现代化的方法,从而帮助企业在竞争激烈的市场中脱颖而出。
26 0
|
14天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
61 6
下一篇
无影云桌面