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

每次,有新的不需要认证的,都需要添加,忘了手动添加就会出问题。能不能添加一个自定义注解,在不需要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 注解来决定是否进行权限校验。
例如:

完整的代码如下:
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);
}
}
}