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

  1. All requests are approved firstnginxLoad and forward
  2. API GatewayResponsible 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
  • @EnableDiscoveryClientUsed 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=1This 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

  • managementConfiguration 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…

Please follow my official account