We can choose a lot of components to build microservice cluster by using SpringCloud technology stack. Since some components have closed source or stopped working, we mainly choose Spring-Cloud-Alibaba as our technology stack.
- Service registration and Discovery:
nacos-discovery
- Unified Configuration management:
nacos-config
- Microservice Gateway:
spring cloud gateway
Since NACOS itself is already a complete service, it can be installed and used directly by referring to the official documentation. Here, it focuses on how to use the SpringCloud Gateway to implement routing and forwarding and identity authentication.
1. Microservice architecture
- All requests are approved first
nginx
Load and forward API Gateway
Responsible for route forwarding and identity authentication in microservices
2. Implement route forwarding
1. Import the Gateway package
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
Copy the code
Note that: If an error occurs during startup, a message is displayed indicating that the springMvc found in the dependency is incompatible with the Gateway, and references related to spring-boot-starter-web need to be deleted
********************************************************** Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. Please remove spring-boot-starter-web dependency. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *Copy the code
2. Add a startup class
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
Copy the code
@EnableDiscoveryClient
Used to register and discover services in a cluster
3. Configure the routing table
The configuration file should be YAML, which has a clear structure and is easy to read
spring:
application:
name: cloud-api # service name
cloud:
nacos:
discovery:
server-addr: 127.0. 01.: 8848 # nacos server address
gateway:
routes:
- id: cloud-user
uri: lb://cloud-user # backend service name
predicates:
- Path=/user/** # route address
filters:
- StripPrefix=1 # remove prefix
server:
port: 8000
# Use it to expose monitoring indicators
management:
endpoints:
web:
exposure:
include: "*"
Copy the code
StripPrefix=1
This command is used to remove the prefix address during route forwarding. If no prefix address exists, the prefix is forwarded to the back-end service. For example:
Request the address is: http://localhost:8000/user/home
If StripPrefix is not added, the address for forwarding to the back-end service is http://{cloud-user}/user/home; otherwise, it is http://{cloud-user}/home
management
Configuration to expose monitoring metrics, available on requesthttp://localhost:8000/actuator/gateway/routesGet all mapped routes
Third, to achieve identity authentication
There are three common authentication methods in distributed systems:
1. Using Session, you can use Spring Security to manage Session, redis to store Session status, and cookies to store client sessionIDS
Advantages:
- Easy to use, client no perception
- High safety
- Good session management support
Disadvantages:
- Not friendly to client application support
- Cross-site cross-end sharing cannot be implemented
- The implementation is relatively complex
- Client Cookie support is required
2. The Token is signed by the server and the user information is stored in Redis. Each request is carried by the client for verification
Advantages:
- Friendly support for multi-terminal sharing
- Friendly support for multi-terminal shared sessions
- The implementation is relatively simple
- High safety
- Cookie support is not required
Disadvantages:
- Maintaining session expiration time is complicated
- The server needs to maintain the session state
3. JWT is signed by the server and does not save the session status. The client needs to verify the validity of each request
Advantages:
- Friendly support for multi-terminal sharing
- Friendly support for multi-terminal shared sessions
- The server has no session status. Procedure
- Cookie support is not required
- Carrying load data
Disadvantages:
- Maintaining session expiration time is complicated
- By default, security is low
- Once issued cannot be revoked, or revocation is more complicated
Simple Token Authentication
In this example, the token is a random code generated by the UUID, and the algorithm is not used for verification. In this way, the client may exhaust the token and constantly query the redis, which may cause risks. In the production environment, certain algorithms can be used to issue tokens, such as encryption and decryption, and valid time stamps, to minimize the impact of forged tokens on servers.
1. The user logs in to save the session status
@Service
public class Session {
@Autowired
private RedisTemplate<String, String> redisTemplate;
Long expireTime = 10800L;
/** * Save session *@param loginUser
*/
public void saveSession(LoginUser loginUser) {
String key = String.format("login:user:%s", loginUser.userToken);
redisTemplate.opsForValue().set(key, JSON.toJSONString(loginUser),
expireTime, TimeUnit.SECONDS);
}
/** * get session *@param token
* @return* /
public LoginUser getSession(String token){
String key = String.format("login:user:%s", token);
String s = redisTemplate.opsForValue().get(key);
if (Strings.isEmpty(s)){
return null;
}
returnJSON.parseObject(s, LoginUser.class); }}Copy the code
When saving the session status, you need to set the expiration time, which is not too long or too short. Consider further how to refresh the session expiration time.
2. AddAuthCheckFilterIntercepts routing requests
@Slf4j
@Component
public class AuthCheckFilter extends AbstractGatewayFilterFactory {
@Autowired
private Session session;
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
1. Obtain the token
String token = request.getHeaders().getFirst("token");
log.info("Current requested URL :{}, method:{}", request.getURI().getPath(), request.getMethodValue());
if (Strings.isEmpty(token)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 2. Verify that the user has logged in
LoginUser loginUser = this.session.getSession(token);
if (loginUser == null) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 3. Pass the user name to the back-end service
ServerWebExchange build;
try {
ServerHttpRequest host = exchange.getRequest().mutate()
.header("X-User-Name", loginUser.userName)
// Chinese characters need encoding
.header("X-Real-Name", URLEncoder.encode(loginUser.realName, "utf-8"))
.build();
build = exchange.mutate().request(host).build();
} catch (UnsupportedEncodingException e) {
build = exchange;
}
returnchain.filter(build); }; }}Copy the code
This interceptor is used to verify that the request is logged in, otherwise it returns the 401 status and passes the user session information to the back-end service.
3. The configuration of the Filter
Configure the routing filters to be validated in the YML configuration file of the Gateway project: AuthCheckFilter
spring:
gateway:
routes:
- id: cloud-user
uri: lb://cloud-user # backend service name
predicates:
- Path=/user/** # route address
filters:
- name: AuthCheckFilter Session authentication
- StripPrefix=1 # remove prefix
Copy the code
Thus, the authentication function of the back-end routing address is realized
Complete code
Gitee.com/hypier/barr…