前端面试简历写上微服务项目,面试多了10个

现在出去找工作,简历上不写上微服务的技术,仿佛自己跟不上时代了,面试官更是喜欢盯着**「微服务项目」**来提问。

但其实虽说微服务是主流,随着云原生架构的发展,微服务也是趋势,但很多公司特别是中小公司的中小业务,根本用不上微服务,你说一个简单的内部管理系统,非得上微服务,有点为了微服务而微服务的感觉了😂。

为了大家能有个可放在简历上**「吹逼」的微服务项目,我们在单体版本的基础上又增加了微服务版本,并在接下来的一段时间内,持续分享「单体应用微服务化」**的经验。

今天分享的是,在微服务架构中,「如何做好鉴权」

微服务架构

微服务简而言之就是单个独立的服务,可以**「独立开发」「部署」「维护」。而微服务架构是指的「多个微服务聚合起来的系统」**,这个系统涵盖多个微服务,服务与服务之间的通讯、服务监控、服务熔断降级、服务注册、分布式配置、分布式事务等各种解决方案聚合而成的架构体系。

微服务架构有如下优点:

  • 「提高开发效率」:团队可以并行开发不同的微服务,减少了开发和发布的时间。
  • 「增强可维护性」:小而专注的代码库更易于理解和维护,降低了技术债务。
  • 「灵活的技术选型」:不同的微服务可以根据需要使用最合适的技术栈,而无需在整个系统中保持一致。
  • 「持续交付和部署」:微服务架构支持持续集成和持续交付(CI/CD),使得新功能和修复能够快速上线。
  • 「更好的故障隔离」:一个微服务的故障不会影响其他微服务的正常运行,从而提高系统的可靠性。
  • 「按需扩展」:可以独立地扩展需要高负载处理的微服务,优化资源使用和成本。

鉴权基础

鉴权顾名思义就是需要进行**「权限认证和授权控制」**,你写好的系统不希望谁都可以访问吧?你写的牛逼的接口也不希望哪个人都可以来蹭一下访问吧?那就需要认证和授权。

专业做这块的有 Spring Security 和 Shiro 这两哥们,当然还有一些其他的框架也是可以做的,但无非核心都在做两件事:

  • 「认证」
  • 「授权」

认证,说白了就是登录,传统 web 登录是通过用户名和密码用 Cookie+Session 的方式,这种依赖于服务器本地内存,微服务中,显然不合适。

常见的鉴权方式有以下几种:

用户名和密码

是最传统和常见的鉴权方式,用户通过输入预先设置的用户名和密码进行登录,需要注意密码的存储和传输安全,如使用加盐哈希存储和HTTPS 传输。

多因素认证(MFA)

这是一种增强安全性的方法,通过要求多种不同类型的验证因素来确认用户身份,常见的因素包括:知识因子(密码)、拥有因子(手机验证码)、生物因子(指纹、面部识别)。

OAuth(开放授权)

这是一种一种授权协议,允许第三方应用以有限的权限访问用户资源,而无需暴露用户的凭证。常用于社交登录和API访问控制。

JWT(JSON Web Token)

一种基于 JSON 的开放标准(RFC 7519),用于在各方之间传递声明。JWT包含用户信息和签名,可用于鉴权和授权。我们这次也是采用的这种方式进行的鉴权。

微服务中鉴权

微服务架构中,通常有多个独立服务组成,这些服务可能部署在不同的服务器或数据中心, 鉴权机制需要在**「分布式环境」中有效运作,确保各个服务能安全通信,且需要「有统一认证中心」**,我们先来看一张微服务架构图:

图片

微服务架构图(来源于网络)

通常会有一个单独的微服务来做认证,也就是认证服务,对于微服务系统而言,请求一般分为 2 种:

  • 通过 API 网关的请求
  • 微服务内部请求

对于这两种请求,都需要进行鉴权,但方式是不一样的,

微服务中如何做认证?

微服务中的认证最多的方式是通过 JWT 令牌的方式,但 JWT 实际上是无状态的,也就是没法确定登录的用户啥时候过期,所以大部分情况下会需要结合 Redis 来**「设置状态」**。

将生成的 JWT 字符串在 Redis 上也保存一份,并设置**「过期时间」**,判断用户是否登录时,需要先去 Redis 上查看 JWT 字符串是否存在,存在的话再对 JWT 字符串做解析操作,如果能成功解析,就没问题,如果不能成功解析,就说明令牌不合法。

这是一个简单的流程图:

图片

▲ 认证流程

我的做法是,在认证服务中,检查用户名密码的正确性,正确的话就生成 JWT 字符串,同时再把数据存入到 Redis 上,然后返回 token 信息。登录请求先经过网关,网关再转发到认证服务,下面是一个具体的流程:

图片

▲ 登录认证

微服务中如何做授权?

授权是请求到达每个微服务后,需要对请求进行权限判定,看是否有权限访问,通常不会放在网关中来做。还是在微服务中自己来做。

我们说过,在微服务架构中,请求主要分为 2 种,外部请求和内部请求,下面是不同的授权思路。

外部请求

我的做法是:请求到达网关后,通过微服务的**「自定义请求头拦截器」**(可以放在公共包下面,每个服务都可以引用),配合自定义注解和 AOP,拦截请求头,获取用户和权限信息,然后进行比对,有权限则放行,没权限则抛出异常。

图片

▲ 外部请求授权流程

内部请求

对于内部的请求来说,正常是不需要鉴权的,内部请求可以直接处理。问题是如果使用了 OpenFeign,数据都是通过接口暴露出去的,不鉴权的话,又会担心从外部来的请求调用这个接口,对于这个问题,我们也可以自定义注解+AOP,然后在内部请求调用的时候,额外加一个头字段加以区分。

我采用的是自定义内部请求注解,然后 AOP 控制拦截。

/**
 * 内部认证注解
 * 
 * @author canghe
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interface InnerAuth
{
    /**
     * 是否校验用户信息
     */
    boolean isUser() default false;
}

AOP 的切面控制请求是否携带有内部请求的标识:

/**
 * 内部服务调用验证处理
 *
 * @author canghe
 */
@Aspect
@Component
publicclass InnerAuthAspect implements Ordered {
    @Around("@annotation(innerAuth)")
    public Object innerAround(ProceedingJoinPoint point, InnerAuth innerAuth) throws Throwable {
        String source = ServletUtils.getRequest().getHeader(SecurityConstants.FROM_SOURCE);
        // 内部请求验证
        if (!StringUtils.equals(SecurityConstants.INNER, source)) {
            thrownew InnerAuthException("没有内部访问权限,不允许访问");
        }

        String userid = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USER_ID);
        String username = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USERNAME);
        // 用户信息验证
        if (innerAuth.isUser() && (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username))) {
            thrownew InnerAuthException("没有设置用户信息,不允许访问 ");
        }
        return point.proceed();
    }

因为使用的是 OpenFeign,请求通过 OpenFeign 调用也需要鉴权,所以我实现了 feign.RequestInterceptor 接口来定义一个 OpenFeign 的请求拦截器,在拦截器中,统一为 OpenFeign 请求设置请求头信息。

/**
 * feign 请求拦截器
 *
 * @author canghe
 */
@Component
publicclass FeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        HttpServletRequest httpServletRequest = ServletUtils.getRequest();
        if (StringUtils.isNotNull(httpServletRequest)) {
            Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest);
            // 传递用户信息请求头,防止丢失
            String userId = headers.get(SecurityConstants.DETAILS_USER_ID);
            if (StringUtils.isNotEmpty(userId)) {
                requestTemplate.header(SecurityConstants.DETAILS_USER_ID, userId);
            }
            String userKey = headers.get(SecurityConstants.USER_KEY);
            if (StringUtils.isNotEmpty(userKey)) {
                requestTemplate.header(SecurityConstants.USER_KEY, userKey);
            }
            String userName = headers.get(SecurityConstants.DETAILS_USERNAME);
            if (StringUtils.isNotEmpty(userName)) {
                requestTemplate.header(SecurityConstants.DETAILS_USERNAME, userName);
            }
            String authentication = headers.get(SecurityConstants.AUTHORIZATION_HEADER);
            if (StringUtils.isNotEmpty(authentication)) {
                requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication);
            }

            // 配置客户端IP
            requestTemplate.header("X-Forwarded-For", IpUtils.getIpAddr());
        }
    }

总结

微服务中的鉴权是很关键的,也是系统安全和完整性的最为核心的一步,微服务架构通过其独立性、模块化和灵活性,使得开发、部署和维护大型复杂系统变得更加高效和可控。然而,这种分布式系统带来了新的安全挑战,需要在系统设计中充分考虑和实现有效的鉴权机制。

以上是今天的分享,希望对你有帮助!

我的博客只写前端博文,点击我去看更多喜欢的前端博文,欢迎大家一起讨论学习!【https://blog.csdn.net/qq_29101285?spm=1011.2266.3001.5343】
  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值