【问题标题】:How can a microservice use the security config of another microservice微服务如何使用另一个微服务的安全配置
【发布时间】:2019-11-27 10:32:44
【问题描述】:

我有一个用户微服务处理与用户相关的所有事情,包括安全性(创建用户、登录、重置密码......)。 我正在使用 JWT Token 来保证安全性。

我的配置安全性如下所示:


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        securedEnabled = true,
        jsr250Enabled = true,
        prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    CustomUserDetailsService customUserDetailsService;

    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * the main Spring Security interface for authenticating a user
     *
     * @return the {@link AuthenticationManager}
     * @throws Exception
     */
    @Bean(BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * create an AuthenticationManager instance
     *
     * @param auth AuthenticationManagerBuilder used to create the instance of AuthenticationManager
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(customUserDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    /**
     * configure security functionality, add rules to protect resources
     * define what route can be accessed without authentication
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().disable();
        http
                .cors()
                .and()
                .csrf()
                .disable()
                .exceptionHandling()
                .authenticationEntryPoint(unauthorizedHandler)
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/h2-console/**")
                .permitAll()
                .antMatchers("/api/auth/**")
                .permitAll()
                .antMatchers(HttpMethod.GET, "/api/user/**")
                .permitAll()
                .anyRequest()
                .authenticated();

        // Add our custom JWT security filter
        http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

我想做的是使用用户微服务来保护另一个微服务(目前是基本的 CRUD)。

我在CRUD微服务中创建了一个feign接口

@FeignClient(name="UserMicroservice", url="http://localhost:8080")
public interface UserClient {

    @PostMapping(value = "/api/auth/login")
    AuthTokenDto authenticateUser(@RequestBody LogInDto logInDto);
}

还有一个控制器

@RestController
public class AuthController {

    @Autowired
    UserClient userClient;

    @PostMapping("/api/auth/login")
    public AuthTokenDto authenticate(@RequestBody LogInDto logInDto) {

        AuthTokenDto token = userClient.authenticateUser(logInDto);

        return token;
    }
}

这样就成功调用了用户微服务并获取了jwt token。

但是我不知道如何让我的 CRUD 微服务使用用户微服务的安全配置。

那么,基本上我可以做些什么来使用我的用户微服务来保护我的 CRUD 微服务的端点?

到目前为止,我无法自己找到解决方案或搜索互联网。

【问题讨论】:

  • 在这样的架构中,微服务通常共享一个共同的秘密。 JWT 中的所有其他内容都是独立的(并已签名)。

标签: java spring jwt microservices feign


【解决方案1】:

我建议您,将令牌保存在 redis 数据库中并在您的所有微服务中实现安全层,并且每次您的微服务接收请求时,如果令牌存在,则在 redis 中实现 JWT 搜索的类。

我是这样实现的

public class JWTAuthorizationFilter extends BasicAuthenticationFilter{

public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {
    super(authenticationManager);
}

@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
                throws IOException, ServletException {
        String header = req.getHeader(Constantes.HEADER_AUTHORIZACION_KEY);
        Logger.getLogger(JWTAuthorizationFilter.class.getCanonicalName()).log(Level.INFO, "HEADER: "+header);
        if (header == null || !header.startsWith(Constantes.TOKEN_BEARER_PREFIX)) {
                chain.doFilter(req, res);
                return;
        }
        UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(req, res);
}

private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(Constantes.HEADER_AUTHORIZACION_KEY);
        Logger.getLogger(JWTAuthorizationFilter.class.getCanonicalName()).log(Level.INFO, "token: "+token);
        if (token != null) {
                // Se procesa el token y se recupera el usuario.
                Jedis jedis = new Jedis(SystemVariables.getDataBaseRedisIp());
                String key = jedis.get(token);
                Logger.getLogger(JWTAuthorizationFilter.class.getCanonicalName()).log(Level.INFO, "key: "+key);
                String user = JWT.require(Algorithm.HMAC256(key)).build()
                        .verify(token.replace(Constantes.TOKEN_BEARER_PREFIX, ""))
                        .getSubject();

                if (user != null) {
                        return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
                }
                return null;
        }
        return null;
}

并在每个 http 请求上添加带有生成令牌的标头授权,例如:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTU2NDEwNjMzNX0.HzG2nKUReCsrEZZOQLH8cuh3yfuP4VX0tkDvWTS8_s8

【讨论】:

    猜你喜欢
    • 2020-07-06
    • 1970-01-01
    • 2020-04-27
    • 2020-06-16
    • 1970-01-01
    • 2018-12-27
    • 2018-03-04
    • 2020-05-31
    • 1970-01-01
    相关资源
    最近更新 更多