微服务:实现身份验证和API网关

简介:

我们将探讨如何设置身份验证和API网关。我们将深入了解Auth Service和API Gateway的配置细节和基本代码片段。

创建Auth服务:为微服务添加身份验证

Auth服务是我们系统中管理用户身份验证的重要部分。我们将指导您完成设置此基本服务所需的代码和配置。

应用程序配置:

下面是Auth Service的application.yml文件:

yaml 复制代码
spring:
  application:
    name: auth-service
  data:
    mongodb:
      uri: mongodb+srv://userid:passowrd@cluster0.gxgeeii.mongodb.net/?retryWrites=true&w=majority
      database: ams
server:
  port: 9003
eureka:
  instance:
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

因为我们使用Mongo-DB来存储数据。

1.存储库和模型类

AccountRepo.java
AccountRepo是Spring Data MongoDB存储库接口。它扩展了MongoRepository,并允许您在MongoDB中对Account集合执行各种操作。在本例中,它包含一个自定义方法findByUserName,用于通过用户名查找帐户。

java 复制代码
@Repository
public interface AccountRepo extends MongoRepository<Account, Integer> {
    Account findByUserName(String username);
}

模型类别:

typescript 复制代码
//Create Account.java Model class
@Data
@Document(collection = "accounts")
public class Account {
    @Id
    private Integer id;
    private String firstName;
    private String lastName;
    private String userName;
    private String createdAt;
    private String password;
    @CreatedDate
    private LocalDate createdDate;
}
//Create LoginRequest.java Model class
@Data
public class LoginRequest {
    private String username;
    private String password;
}
//Create LoginResponse.java Model class
@Data
public class LoginResponse {
    private String token;
    private String userName;
}

2. Auth Controller(AuthController.java):

AuthController负责处理用户注册、登录和令牌验证。

less 复制代码
package com.auth.controller;

imports ****

@RestController
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private AuthService authServicee;



    @PostMapping("/register")
    public Account createAmsAccount(@RequestBody Account account) throws Exception {
        return authServicee.saveAccount(account);
    }


    @PostMapping("/login")
    public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest loginRequest) {
        Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
        String token ;
        if (authenticate.isAuthenticated()) {
            token = authServicee.generateToken(loginRequest.getUsername());
        } else {
            throw new RuntimeException("invalid access");
        }
        LoginResponse response = LoginResponse.builder()
                .token(token)
                .userName(loginRequest.getUsername()).build();
        return ResponseEntity.ok(response);
    }

    @GetMapping("/validate")
    public String validateToken(@RequestParam("token") String token) {
        try {
            authServicee.validateToken(token);
        } catch (BadCredentialsException e) {
            throw new BadCredentialsException(" Invalid Token ");
        }
        return "Token is valid";
    }


}

在这段代码中,我们定义了用于注册、登录和令牌验证的端点。使用Spring Security和JWT令牌执行用户身份验证。

3.安全配置(authConfig.java):

authConfig类包含与安全相关的配置。它定义了自定义的UserDetailsService、安全过滤器链、密码编码和身份验证提供程序。

java 复制代码
@Configuration
@EnableWebSecurity
public class authConfig {

    @Bean
    public UserDetailsService userDetailsService() {
        return new CustomUserDetailsService();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.csrf().disable()
                .authorizeHttpRequests()
                .requestMatchers("/auth/register", "/auth/login", "/auth/validate").permitAll()
                .and()
                .build();
    }

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

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService());
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }
}

在这个配置类中,我们定义了安全设置,包括UserDetailsService、身份验证过滤器链、密码编码和身份验证提供程序。

4.自定义用户详细信息服务(CustomUserDetailsService.java):

CustomUserDetailsService实现了UserDetailsService接口,为身份验证提供了用户详细信息。

java 复制代码
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private AccountRepo accountRepo;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        try {
            Account account = accountRepo.findByUserName(username);
            String userName = account.getUserName();
            String password = account.getPassword();
            return new User(userName, password, new ArrayList<>());
        } catch (Exception e) {
            throw new UsernameNotFoundException(e.toString());
        }
    }
}

这个类从数据库中检索用户详细信息,使Spring Security能够对用户进行身份验证。

5.认证服务(AuthService.java):

AuthService类管理用户帐户操作,包括保存帐户、生成令牌和验证令牌。

typescript 复制代码
@Service
public class AuthService {

    @Autowired
    private AccountRepo accountRepo;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtService jwtService;

    public Account saveAccount(Account account) throws Exception {
        account.setPassword(passwordEncoder.encode(account.getPassword()));
        return accountRepo.save(account);
    }

    public String generateToken(String username) {
        return jwtService.generateToken(username);
    }

    public void validateToken(String token) {
        jwtService.validateToken(token);
    }
}

这个服务类使用JWT处理用户帐户操作、密码加密和令牌管理。

6. JWT服务(JwtService.java):

JwtService类负责JWT令牌的生成和验证。

typescript 复制代码
@Service
public class JwtService {

    public static final String SECRET = "Random generate secret key";

    public void validateToken(final String token) {
        Jwts.parserBuilder().setSigningKey(getSignKey()).build().parseClaimsJws(token);
    }

    public String generateToken(String userName) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, userName);
    }

    private String createToken(Map<String, Object> claims, String userName) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(userName)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 30))
                .signWith(getSignKey(), SignatureAlgorithm.HS256).compact();
    }

    private Key getSignKey() {
        byte[] keyBytes = Decoders.BASE64.decode(SECRET);
        return Keys.hmacShaKeyFor(keyBytes);
    }
}

JwtService类负责生成和验证JWT令牌,增强Auth Service的安全性。

创建API网关:管理微服务通信。

API网关充当所有请求的入口点,并管理将这些请求路由到适当的微服务。以下是如何配置它:

应用程序配置:

API网关的application.yml文件:

yaml 复制代码
spring:
  application:
    name: api-gateway
  main:
    allow-bean-definition-overriding: true
  cloud:
    gateway:
      routes:
        - id: account-service
          uri: lb://account-service
          predicates:
            - Path=/account/**
          filters:
            - AuthenticationFilter

        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/user/**
          filters:
            - AuthenticationFilter

        - id: auth-service
          uri: lb://auth-service
          predicates:
            - Path=/auth/**
eureka:
  instance:
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
server:
  port: 9000

ApigatewayApplication.java

typescript 复制代码
package com.apigateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class ApigatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApigatewayApplication.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

这是API网关的主类。它被注释为@SpringBootApplication以指示它是Spring靴子应用程序。@EnableDiscoveryClient注释支持使用尤里卡进行服务发现。@LoadBalanced注释配置了一个RestTemplate,它可以在服务实例之间进行负载平衡。

AuthenticationFilter.java

kotlin 复制代码
package com.apigateway.filter;

import com.apigateway.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ExceptionHandler;

@Component
public class AuthenticationFilter extends AbstractGatewayFilterFactory<AuthenticationFilter.Config> {

    @Autowired
    private RouteValidator validator;

    @Autowired
    private JwtUtil jwtUtil;

    public AuthenticationFilter() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            if (validator.isSecured.test(exchange.getRequest())) {
                if (!exchange.getRequest().getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
                    throw new RuntimeException("Missing authorization header");
                }

                String authHeader = exchange.getRequest().getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);
                if (authHeader != null && authHeader.startsWith("Bearer ")) {
                    authHeader = authHeader.substring(7);
                }
                try {
                    jwtUtil.validateToken(authHeader);
                } catch (Exception e) {
                    System.out.println("Invalid access...!");
                    throw new RuntimeException("Unauthorized access to the application");
                }
            }
            return chain.filter(exchange);
        });
    }

    public static class Config {

    }
}

AuthenticationFilter是API网关的自定义过滤器。它检查传入请求中是否存在Authorization头。如果头部存在并且包含有效的JWT令牌,则允许请求通过。否则,它会抛出一个未经授权的访问RuntimeException

此过滤器确保只有具有有效JWT令牌的经过身份验证的请求才能访问安全端点。它使用JwtUtil来验证JWT令牌。

RouteValidator.java

java 复制代码
package com.apigateway.filter;

import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.function.Predicate;

@Component
public class RouteValidator {

    public static final List<String> openApiEndpoints = List.of(
            "/auth/register",
            "/auth/login",
            "/eureka"
    );

    public Predicate<ServerHttpRequest> isSecured =
            request -> openApiEndpoints
                    .stream()
                    .noneMatch(uri -> request.getURI().getPath().contains(uri));
}

这些类和配置文件有助于实现API网关,该网关将请求路由到适当的服务,并根据指定的路由强制执行安全检查。

相关推荐
麦兜*12 分钟前
SpringBoot 2.x→3.0升级实战:Jakarta EE兼容性改造清单
java·spring boot·后端·spring·系统架构·maven·springcloud
天天摸鱼的java工程师1 小时前
蚂蚁金服面试官:你能从JVM源码解释STW吗?
java·后端·面试
liangdabiao1 小时前
包学会!WooCommerce开源电商的基础架构 - 简要介绍它的核心对象 - 有用有料
后端·架构
未来影子1 小时前
MCP的SSE重连机制,源码解析
人工智能·后端
bobz9651 小时前
kubevirt 替换为 hostnetwork 的优势
后端
大象席地抽烟1 小时前
Nginx Ingress 证书
后端
心之语歌1 小时前
Java 设计 MCP SSE 配置
java·后端
华仔啊1 小时前
推荐一款比Cursor更懂中国程序员的AI编程工具
前端·后端
海风极客1 小时前
Ping命令这种事情用Go也能优雅实现
后端·go·github
天天摸鱼的java工程师2 小时前
“你能从字节码层面解释JVM内存模型吗?”——面试官的死亡提问
java·后端·面试