当前位置: 首页 > 知识库问答 >
问题:

如何在微服务架构中实现基于角色的安全性[关闭]

田阳泽
2023-03-14

我有一个带有4个微服务、eureka服务器和一个集中式API网关的Spring Boot应用程序。

所有外部流量都通过API网关进入我的微服务。

我的API网关(Zuul)正在验证和验证JWT令牌。

JWT令牌由我的一个微服务在用户登录后生成(用户微服务),该令牌包含用户Id和他的角色/权限。

现在我想在网关以外的微服务中存在的方法上实现基于角色的安全性。

我尝试过使用@PreAuthorize,但它在网关外不起作用(显然为了使其工作,我必须在我的微服务中的SecurityContextHolder中设置Spring Security身份验证对象并使用权限填充它)。

那么,有什么解决方案可以实现这种安全性呢?

在微服务架构中设置安全性的最佳设计是什么?

API网关级别的身份验证和微服务级别的授权?

我是否需要在微服务中使用Spring Security性,或者在API网关级别验证JWT后传递角色(将它们附加到请求中),例如创建自己的注释并使用spring AOP处理授权?

共有3个答案

邓阳嘉
2023-03-14

如果您的API gateway也是创建JWT令牌并使用私钥对其进行签名的人,并且为了验证您是否使用API gateway中的公钥,那么您就是指定该JWT令牌结构的人,并且您应该能够将角色编码到该JWT中(例如,它可以是范围参数,但所有用户通常都可以访问所有可能的范围)。然后,您可以将spring boot配置为自动解析来自该JWT的组角色(设置SecurityContextHolder角色的右侧),并且无需任何修改即可使用@PreAuthorize注释。

如果您的API网关仅针对第三方授权服务器(签署并构建JWT的服务器)验证JWT令牌,并使用来自该服务器的公钥,那么您必须实现一些自定义的基于角色的访问机制。我想到的一个方法是实现第二级Oauth2身份验证,该身份验证只用于微服务和API网关之间的请求,使用某种“内部”JWT。例如,请参见下图:

由于您通过API网关代码定义内部JWT的结构,因此您可以设置自定义属性的类似角色:(管理员、用户等)。例如,这可以通过用户名、id、电子邮件来解决,这些用户名、id、电子邮件是从第三方授权服务器的外部JWT提供的。因此,您需要在API网关代码中保留一些映射,例如:

(userId: 12563) => Admin group
(userId: 45451) => User group

由于您的微服务使用JWT进行身份验证,因此您可以使用Spring引导资源服务器来设置身份验证并将其配置为从您的自定义结构化内部JWT自动解析组(您在SecurityContextHolder中提到的对象)。这样,您可以简单地在微服务中使用@PreAuthorize注释,因此您不必创建自定义注释。请注意,这只是为了解决我在第一种情况下指定的第二种情况,您已经控制了JWT令牌。

夹谷斌蔚
2023-03-14

目前这个问题很广泛,因为你们的微服务流量的性质还不清楚。

>

  • 假设所有通过API网关传输到微服务的外部流量。

    • 您不需要在API网关和内部微服务中验证JWT两次。如果JWT无效,请求将永远不会到达您的微服务

    假设外部流量可以通过您的API网关以及直接到您的微服务。

    • 现在,您需要在API网关和微服务中验证它

    使现代化

    • 我不了解Zuul API网关。这只是针对以下问题:

    我曾尝试使用@PreAuthorize,但它在网关之外无法工作(显然,为了使其工作,我必须在我的微服务的SecurityContextHolder中设置一个Spring Security身份验证对象,并用权限填充它)。

        public class PreAuthenticatedUserRoleHeaderFilter 
            extends GenericFilterBean {
    
        public void doFilter(ServletRequest servletRequest, 
                             ServletResponse servletResponse,
                             FilterChain chain) 
                throws IOException, ServletException {
    
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            String rolesString = //extract the roles
            String userName = // extract the username
    
            List<GrantedAuthority> authorities 
               = AuthorityUtils.commaSeparatedStringToAuthorityList(rolesString);
    
    
            PreAuthenticatedAuthenticationToken authentication 
                    = new PreAuthenticatedAuthenticationToken(
                                        userName, null, authorities);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            chain.doFilter(servletRequest, servletResponse);
        }
    }
    
        @Configuration
        @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, 
            jsr250Enabled = true)
        public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            PreAuthenticatedUserRoleHeaderFilter authFilter
                    = new PreAuthenticatedUserRoleHeaderFilter();
            http.
                    antMatcher("/**")
                    .csrf()
                    .disable()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .addFilterBefore(authFilter, 
                                     BasicAuthenticationFilter.class)
                    .authorizeRequests()
                    .anyRequest()
                    .authenticated();
          }
    
        }
    

  • 扶誉
    2023-03-14

    在Spring5微服务中,您将能够找到一个基础来开发具有您正在寻找的几个必备条件的微服务架构:

    • 使用Eureka的注册表服务器
    • 带Zuul的网关服务器

    关于安全性,我开发了两种不同的微服务:

    • 带Jwt的Spring Oauth2

    正如您在此处看到的,大多数重要的API都使用Swagger进行了很好的记录,并且所有记录的API都可以使用唯一的网关Url访问。

    对于每个微服务的所有类,都开发了JUnit测试。

    在这一点上,我做了几个决定:

    1.网关不是验证安全性的微服务。

    因为将网关用作“防火墙”是一种不太灵活的方法。我想决定哪些微服务需要安全性,每个微服务都应该在内部管理角色可以访问每个endpoint。总之,每个微服务都必须使用授权/身份验证,但它不需要知道该功能是如何实现的。

    2.处理安全问题的具体微服务

    正如我告诉你的,我开发了两种不同的方法,因为我想“玩”不同的选项/方法。最重要的优点是封装,如果“明天”我决定通过任何其他选项更改Jwt,我只需要修改这些选项,使用它们的微服务将保留相同的代码(我将很快向您解释集成是如何完成的)

    我将解释如何将安全功能集成到:

    • Pizza service easy microservice是该架构的一部分

    1.每个管理用户和角色的应用程序都将在security microservice中包含一个类似于下一个文件夹的文件夹,用于定义其模型、存储库以获取所需信息等

    2.此处定义了安全微服务的全局endpoint。如您所见,它们基本上与2个DTO一起工作:

    • 认证信息发送至

    主要优点是,只有安全微服务知道有关该功能是如何完成的详细信息,其他使用它的微服务将收到包含所需信息的众所周知的Dtos。

    3.在pizza服务中,安全集成主要定义在以下三个类中:

    • SecurityContextRepository从标头中获取授权令牌并将其发送到SecurityManager
    • SecurityManager使用提供的“授权令牌”调用security-jwt-service(它不知道它是Jwt还是任何其他东西)并接收一个众所周知的UsernameAuthoritiesDto(将其转换为Spring类UsernamePasswordAuthentiationToken的对象)
    • WebSecurityConfiguration全局安全配置。

    现在,您可以在endpoint中包含所需的基于角色的安全性:

    • 控制器示例

    >

  • pices-service是使用Webflow开发的,您可以在这里的order-service中看到基于MVC微服务的等效集成(在这种情况下,我使用了“其他安全服务”,但很容易对其进行调整)。

    为了提高安全性并遵循“Oauth方法”,对security-jwt-service的请求也需要包括Basic身份验证。正如您在SecurityManager类中看到的:

    private String buildAuthorizationHeader(String username, String password) {
      String auth = username + ":" + password;
      byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
      return "Basic " + new String(encodedAuth);
    }
    

    数据库中存储该信息的表与用于管理每个应用程序的安全配置的表相同:security。jwt_客户_详细信息

  •  类似资料:
    • Navicat 提供强大的工具让你管理服务器用户帐号和数据库对象的权限。所有用户和权限的信息都保存于服务器。在主窗口中,点击 “用户”或 “角色”来打开用户或角色的对象列表。

    • Navicat 提供强大的工具让你管理服务器用户帐号和数据库对象的权限。所有用户和权限的信息都保存于服务器。在主窗口中,点击 “用户”来打开用户或角色的对象列表。

    • Navicat 提供强大的工具让你管理服务器用户帐号和数据库对象的权限。所有用户和权限的信息都保存于服务器。在主窗口中,点击 “用户”或 “角色”来打开用户或角色的对象列表。

    • 翻译自 Martin Fowler 网站 Microservices 一文。文章篇幅较长,阅读需要一点耐心,本人水平有限,若有不妥之处,还请各位帮忙指正,谢谢。 过去几年中出现了“微服务架构”这一术语,它描述了将软件应用程序设计为若干个可独立部署的服务套件的特定方法。尽管这种架构风格尚未有精确的定义,但围绕业务能力、自动部署、端点智能以及语言和数据的分散控制等组织来说,它们还是存在着某些共同特征。

    • 我读了一些文章,看了一些视频,但在为这些微服务提供服务方面,没有找到具体的建议。我的理解是,他们应该使用自己的应用程序服务器。 我的问题是它们应该部署在不同的服务器上,还是没关系。 当它们在同一台服务器(计算机)上提供服务时,不会有端口冲突吗?

    • 主要内容:一、读写锁的介绍,二、微服务注册中心的读写锁优化一、读写锁的介绍 上一篇文章:《年底被裁,复习Java锁的底层准备面试》聊了一下java并发包的公平锁和非公平锁。 这篇文章来聊一下读写锁。所谓的读写锁,就是将一个锁拆分为读锁和写锁两个锁,然后你加锁的时候,可以加写锁,也可以加读锁。如下面代码所示: 如果有一个线程加了写锁,那么其他线程就不能加写锁了,同一时间只能允许一个线程加写锁。因为加了写锁就意味着有人要写一个共享数