Supplementary gateway authentication for sso single sign-on


foreword

 


1. Authentication process

Based on sso single sign-on, after the user logs in, in order to ensure that the user can access other microservice resources. Let a token that does not expire for a long time be put into redis and use the function of redis to set the expiration time, and let the successfully logged-in token keep refreshing the expiration time in redis. It is realized that as long as the user is still operating the service, the token in redis will always exist, so that single sign-on can be realized and used everywhere.

For authentication, it is to put the user's permission code in the token and use aop to compare whether the permission code of the incoming request from the front end is the same as the user's permission code. If they are the same, let it access the functions it has. If not, return an error code. It uses a custom annotation to make the interface with the annotation and the permission code pass the verification all the time, and then if the current user does not have the permission, an exception of insufficient permission is thrown, and the exception of insufficient permission is uniformly handled through global exception capture.

2. Implementation steps

2.1 Authority tool module

Create a new security module under common

Import required dependencies

<dependencies>
    <!--Introduce common-core-->
    <dependency>
        <groupId>com.xin</groupId>
        <artifactId>xin-common-core</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <!--Still aop aspect-oriented dependency-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <!--servlet request dependency -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
    </dependency>
    <!--soring web dependencies-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
    </dependency>
</dependencies>

/**
 * 有权限的自定义注解
 * @author Ren
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasPermission {

    String value() default "";
}

custom exception class 

public class PermissionException extends RuntimeException {

    public PermissionException(String msg){
        super(msg);
    }

    public PermissionException() {
    }
}

Global exception handling class

@RestControllerAdvice
public class MyExceptionHandler {
    @ExceptionHandler(value = PermissionException.class)
    public Result<String> handle01(PermissionException e){
        return new Result<>(4001,e.getMessage());
    }
}

 Implementation of aop aspect class


@Aspect
@Component
public class PermissionAspect {


    /**
     * 定义切点方法
     */
    @Pointcut(value = "@annotation(com.rcg.security.annotation.HasPermission)")
    public void pointcut() {

    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取方法对象。
        MethodSignature methodSignatur= (MethodSignature) joinPoint.getSignature();
        Method method = methodSignatur.getMethod();
        //获取方法上HasPermission
        HasPermission annotation = method.getAnnotation(HasPermission.class);
        if(annotation!=null){
            String permission = annotation.value();
            //在springmvc任意唯一获取request对象。
            HttpServletRequest request = WebUtils.getRequest();
            String token = request.getHeader("token");
            //解析token
            Map<String, Object> map = JwtUtil.getTokenChaim(token);
            List<String> authorities = (List<String>) map.get("authorities");


            if(!authorities.contains(permission)){
                throw new PermissionException("权限不足");
            }

        }

        return joinPoint.proceed();

    }

}

http request tool class

public class WebUtils {
    /** 获取request对象 **/
    public static HttpServletRequest getRequest(){

        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null){

            return null;
        }
        return ((ServletRequestAttributes)requestAttributes).getRequest();
    }
    /** 获取response对象 **/
    public static HttpServletResponse getResponse(){

        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null){

            return null;
        }
        return ((ServletRequestAttributes)requestAttributes).getResponse();
    }
}

 2.2 Modification of gateway module

Mainly add a login filter to deal with the token time refresh problem

Introduce dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <dependency>
        <groupId>com.xin</groupId>
        <artifactId>xin-common-core</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
</dependencies>
 

Configuration file application.yml

server:
  port: 8086
spring:
  application:
    name: cai-gateway
  redis:
    host: localhost
    port: 6379
  cloud:
    gateway:
      routes:
        - id: cai-sso
          uri: lb://cai-sso
          predicates:
            - Path=/login

        - id: cai-system
          uri: lb://cai-system
          predicates:
            - Path=/system/**

Login filter class


@Component
public class LoginFilter implements GlobalFilter, Ordered {


    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取请求对象和响应对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //2.获取请求路径
        String url = request.getPath().toString();
        //2.1 判断放行请求为login的
        if ("/login".equals(url)){
            return chain.filter(exchange);

        }
        //3.获取请求头
        String token = request.getHeaders().getFirst("token");

        //判断token 不为空 有效 redis不过期
        if (StringUtils.hasText(token)
                && JwtUtil.verifyToken(token)
                &&stringRedisTemplate.hasKey(token)){

            //刷新token时间 验证通过继续延长token在redis中的过期时间
            stringRedisTemplate.expire(token,30, TimeUnit.MINUTES);
            //放行
            return chain.filter(exchange);
        }


        //所有验证都失败的情况
        Result<String> result=new Result<>(5001,"登录失效");
        //3.3作JSON转换
        byte[] bytes = JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8);

        //3.4调用bufferFactory方法,生成DataBuffer对象
        DataBuffer buffer = response.bufferFactory().wrap(bytes);

        //4.调用Mono中的just方法,返回要写给前端的JSON数据
        return response.writeWith(Mono.just(buffer));
    }


    /**
     * 过滤器的优先级 0是最高级
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

Configuration of the startup class

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class GateWayApp {

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

 

2.3 Modification of system business modules 

Introduce the authentication tool module

<dependency>
    <groupId>com.xin</groupId>
    <artifactId>xin-common-security</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

Add annotations for scanning aop annotations on the main startup class

@ComponentScan(basePackages = {"com.xin.system","com.rcg.security"})

Modify the api that returns the front end 

query and insert have permissions for the current user update is not the user's permissions

test

First log in to get the token and then access the microservice module test through the gateway

 

 

 The authentication function is successfully implemented.

 

 

 

 

 

 

 

 

 


Summarize

none

Guess you like

Origin blog.csdn.net/qq_55648724/article/details/129187647