首頁 > Java > java教程 > Springboot怎麼實現通用Auth認證

Springboot怎麼實現通用Auth認證

王林
發布: 2023-05-14 11:31:05
轉載
1159 人瀏覽過

傳統AOP

對於這種需求,首先想到的當然是 Spring-boot 提供的 AOP 接口,只需要在 Controller 方法前添加切點,然後再對切點進行處理即可。

實作

其使用步驟如下:

  1. #使用@Aspect 宣告切面類別WhitelistAspect;

  2. #在切面類別內加入一個切點whitelistPointcut(),為了實現此切點靈活可組裝的能力,這裡不使用execution 全部攔截,而是添加一個註解@Whitelist,被註解的方法才會校驗白名單。

  3. 在切面類別中使用 spring 的 AOP 註解 @Before 宣告一個通知方法 checkWhitelist() 在 Controller 方法被執行之前校驗白名單。

切面類別偽代碼如下:

 @Aspect
  public class WhitelistAspect {

    @Before(value = "whitelistPointcut() && @annotation(whitelist)")
    public void checkAppkeyWhitelist(JoinPoint joinPoint, Whitelist whitelist) {
        checkWhitelist();
        // 可使用 joinPoint.getArgs() 获取Controller方法的参数
        // 可以使用 whitelist 变量获取注解参数
    }

    @Pointcut("@annotation(com.zhenbianshu.Whitelist)")
    public void whitelistPointCut() {
    }
  }
登入後複製

在Controller方法上新增 @Whitelist 註解實作功能。

擴展

本例中使用了註解來宣告切點,並且我實作了透過註解參數來宣告要校驗的白名單,如果之後還需要新增其他白名單的話,如透過UID 來校驗,則可以為此註解添加uid() 等方法,實現自訂校驗。

此外,spring 的AOP 還支援execution(執行方法)、bean(符合特定名稱的Bean 物件的執行方法)等切點宣告方法和 @Around(在目標函數執行中執行) 、@After(方法執行後) 等通知方法。

如此,功能已經實現了,但領導並不滿意=_=,原因是專案中 AOP 用得太多了,都用濫了,建議我換個方式。嗯,只好搞起。另外關注:碼猿技術專欄,在後台回覆:「面試寶典」可以獲取,高清PDF最新版3625頁互聯網大廠面試題。

Interceptor

Spring 的 攔截器(Interceptor) 實作這個功能也非常適合。顧名思義,攔截器用於在 Controller 內 Action 被執行前透過一些參數判斷是否要執行此方法,要實作一個攔截器,可以實作 Spring 的 HandlerInterceptor 介面。

實作

實作步驟如下:

  1. #定義攔截器類別 AppkeyInterceptor 類別並實作 HandlerInterceptor 介面。

  2. 實作其preHandle() 方法;

  3. #在preHandle 方法內透過註解和參數判斷是否需要攔截請求,攔截請求時介面返回false;

  4. 在自訂的WebMvcConfigurerAdapter 類別內註冊此攔截器;

##AppkeyInterceptor 類別如下:


@Component
public class WhitelistInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Whitelist whitelist = ((HandlerMethod) handler).getMethodAnnotation(Whitelist.class);
        // whitelist.values(); 通过 request 获取请求参数,通过 whitelist 变量获取注解参数
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  // 方法在Controller方法执行结束后执行
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  // 在view视图渲染完成后执行
    }
}
登入後複製

擴充


要啟用攔截器也要明確設定它啟用,這裡我們使用WebMvcConfigurerAdapter 對它進行設定。需要注意,繼承它的的 MvcConfiguration 需要在 ComponentScan 路徑下。


@Configuration
public class MvcConfiguration extends WebMvcConfigurerAdapter {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new WhitelistInterceptor()).addPathPatterns("/*").order(1);
        // 这里可以配置拦截器启用的 path 的顺序,在有多个拦截器存在时,任一拦截器返回 false 都会使后续的请求方法不再执行
    }
}
登入後複製

也需要注意,攔截器執行成功後回應碼為 200,但回應資料為空。

當使用攔截器實現功能後,領導終於祭出大招了:我們已經有一個Auth 參數了,appkey 可以從Auth 參數裡取到,可以把在不在白名單作為Auth 的一種方式,為什麼不在Auth 時校驗? emmm… 吐血中。

ArgumentResolver

參數解析器是Spring 提供的用於解析自訂參數的工具,我們常用的@RequestParam 註解就有它的影子,使用它,我們可以將參數在進入Controller Action之前就組合成我們想要的樣子。 Spring 會維護一個 ResolverList, 在請求到達時,Spring 發現有自訂類型參數(非基本型別), 會依序嘗試這些 Resolver,直到有一個 Resolver 能解析所需的參數。要實作一個參數解析器,需要實作 HandlerMethodArgumentResolver 介面。


實作

  • 定義自訂參數類型AuthParam,類別內有appkey 相關欄位;

  • 定義AuthParamResolver並且實作HandlerMethodArgumentResolver 介面;

  • 實作supportsParameter() 介面方法將AuthParam 與AuthParamResolver 適配起來;

  • resolveArgument() 介面方法解析方法解析方法;

  • ##resolveArgument() 介面方法解析方法解析方法; reqest 物件產生AuthParam 對象,並在此校驗AuthParam ,確認appkey 是否在白名單內;
  • 在Controller Action 方法上簽章內新增AuthParam 參數以啟用此Resolver;


實作的AuthParamResolver 類別如下:


@Component
public class AuthParamResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(AuthParam.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        Whitelist whitelist = parameter.getMethodAnnotation(Whitelist.class);
        // 通过 webRequest 和 whitelist 校验白名单
        return new AuthParam();
    }
}
登入後複製

擴充


當然,使用參數解析器也需要單獨配置,我們同樣在WebMvcConfigurerAdapter內配置:


@Configuration
public class MvcConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new AuthParamResolver());
    }
}
登入後複製

這次實現完了,我還有些不放心,於是在網上查找是否還有其他方式可以實現此功能,發現常見的還有Filter。 ######

Filter

Filter 并不是 Spring 提供的,它是在 Servlet 规范中定义的,是 Servlet 容器支持的。被 Filter 过滤的请求,不会派发到 Spring 容器中。它的实现也比较简单,实现 javax.servlet.Filter接口即可。

由于不在 Spring 容器中,Filter 获取不到 Spring 容器的资源,只能使用原生 Java 的 ServletRequest 和 ServletResponse 来获取请求参数。

另外,在一个 Filter 中要显示调用 FilterChain 的 doFilter 方法,不然认为请求被拦截。实现类似:
public class WhitelistFilter implements javax.servlet.Filter {

@Override
    public void init(FilterConfig filterConfig) throws ServletException {
  // 初始化后被调用一次
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
     // 判断是否需要拦截
       chain.doFilter(request, response); // 请求通过要显示调用
    }

    @Override
    public void destroy() {
     // 被销毁时调用一次
    }
}
登入後複製

扩展

Filter 也需要显示配置:

@Configuration
public class FilterConfiguration {

    @Bean
    public FilterRegistrationBean someFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new WhitelistFilter());
        registration.addUrlPatterns("/*");
        registration.setName("whitelistFilter");
        registration.setOrder(1); // 设置过滤器被调用的顺序
        return registration;
    }
}
登入後複製

以上是Springboot怎麼實現通用Auth認證的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:yisu.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板