怎么通过注解实现shiro不校验url

  • 作者: 凯哥Java(公众号:凯哥Java)
  • shiro学习系列
  • 时间:2023-06-12 15:54
  • 3896人已阅读
简介 在使用shiro的权限认证的时候,有时候,有些链接不需要shiro认证的。比如登录接口。在代码中写死,如下图:每次,有新的不需要认证的,都需要添加,忘了手动添加就会出问题。能不能添加一个自定义注解,在不需要shiro认证的方法或者类上直接加自定义注解来处理?答案:可以。以下为解决步骤:①:添加自定义注解import java.lang.annotation.ElementType;imp

🔔🔔🔔好消息!好消息!🔔🔔🔔

有需要的朋友👉:联系凯哥 微信号 kaigejava2022

在使用shiro的权限认证的时候,有时候,有些链接不需要shiro认证的。比如登录接口。在代码中写死,如下图:

2ff69ff0cd830cdf69e3abb5e51baf1b.png

每次,有新的不需要认证的,都需要添加,忘了手动添加就会出问题。能不能添加一个自定义注解,在不需要shiro认证的方法或者类上直接加自定义注解来处理?

答案:可以。

以下为解决步骤:

①:添加自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ShiroIgnoreAuth {
}

②:在进行权限校验时,可以通过判断方法上是否有 @ShiroIgnoreAuth 注解来决定是否进行权限校验。

例如:

8696a2bca719dabc4ebc3dfb0a843ad2.png

完整的代码如下:

import xxx.LoginServiceImpl;
import xxx.ShiroIgnoreAuth;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.support.RequestContextUtils;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {

    /**
     * 执行登录认证
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        WebApplicationContext ctx = RequestContextUtils.findWebApplicationContext(httpServletRequest);
        RequestMappingHandlerMapping mapping = ctx.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class);
        HandlerExecutionChain handler = null;

        try {
            handler = mapping.getHandler(httpServletRequest);
            HandlerMethod handlerClass = (HandlerMethod)handler.getHandler();
            Class<?> nowClass = handlerClass.getBeanType();
            Method method = handlerClass.getMethod();
            ShiroIgnoreAuth anonymousAccess = AnnotationUtils.getAnnotation(nowClass, ShiroIgnoreAuth.class);
            if (anonymousAccess != null) {
                return true;
            }
            anonymousAccess = AnnotationUtils.getAnnotation(method,ShiroIgnoreAuth.class);
            //如果方法上有 @ShiroIgnoreAuth 注解,则不进行权限校验
            if (anonymousAccess != null) {
                return true;
            }

            //执行登录
            executeLogin(request, response);
            return true;
        } catch (AuthenticationException e) {
            log.error("认证失败",e);
            response401(request, response, e.getMessage());
        } catch (Exception e) {
            //如果没有token,那么就请求转发到到401请求,让401controller返回前端一个请求
            log.error("认证异常",e);
            response401(request, response, "其他异常");
        }
        return false;
    }

    /**
     * Jwt登录
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader(LoginServiceImpl.X_ACCESS_TOKEN);
        JwtToken jwtToken = new JwtToken(token);
        // 提交给realm进行登入,如果错误他会抛出异常并被捕获
        getSubject(request, response).login(jwtToken);
        // 如果没有抛出异常则代表登入成功,返回true
        return true;
    }

    /**
     * 对跨域提供支持
     */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
        // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        return super.preHandle(request, response);
    }

    /**
     * 重定向到
     *
     * @param request
     * @param response
     * @param msg
     */
    private void response401(ServletRequest request, ServletResponse response
            , String msg) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        try {
            // //请求转发401controller
            httpServletRequest.getRequestDispatcher("/login/401/" + msg).forward(request, response);
        } catch (ServletException | IOException e) {
            log.error("重定向时候异常了",e);
        }
    }
}





TopTop