简介:
我们将探讨如何设置身份验证和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网关,该网关将请求路由到适当的服务,并根据指定的路由强制执行安全检查。