Spring Boot がユニバーサル Auth 認証を実装する 4 つの方法!

この記事では、Spring Boot で一般的な認証を実装する 4 つの方法 (従来の AOP、インターセプター、パラメーター パーサー、フィルターを含む) を紹介し、対応するサンプル コードを提供し、最後にそれらの実行順序を参考と学習のために簡単にまとめています。

| はじめに

「最近、私は際限のないビジネス ニーズに圧倒され、息つく暇もありません。ようやくコードというコンフォート ゾーンを突破できる仕事を得ることができました。それを解決するプロセスは非常に曲がりくねっていました。当然のことですが、私はそう感じています」 Java、Tomcat、Spring が私の目を遮っていたベールの層を消去しました。それらに対する新たなレベルの理解が達成されました。

長い間アウトプットしていないので、整理する過程で他のことも学べればと思い、1つの側面を選んで要約します。Java のエコロジーが盛んであるため、以下の各モジュールには Java に特化した多数の記事があります。そこで私は、実践的な問題から始めて、これらの散在する知識をつなぎ合わせて、要約として見ることができる、別の角度を選択しました。各モジュールの最終的な詳細については、公式ドキュメントにアクセスするか、インターネット上の他のブログを読むことができます。

要件はシンプルかつ明確であり、製品によって提起されるコケティッシュな要件とはまったく同じではありません。Web フレームワークに appkey ホワイトリスト検証機能を追加し、そのスケーラビリティが向上することを期待しています通用

このWebフレームワークは、部門の先駆者によってspring-bootをベースに実装されており、ビジネスとSpringフレームワークの間に位置し、ログ出力、関数スイッチ、一般的なパラメータなど、ビジネスに偏ったいくつかの一般的な機能を実行します。分析。通常、ビジネスに対して透過的ですが、最近は要件を作成したり、コードをうまく書くのに忙しくて、その存在にさえ気づきませんでした。

| 方法 1. 従来の AOP

この要件としては、Spring Boot が提供する AOP インターフェースが真っ先に思い浮かびますが、Controller メソッドの前にカットポイントを追加し、そのカットポイントを処理するだけです。

成し遂げる

その使用手順は次のとおりです。

  1. @Aspect アスペクトクラスを宣言するために 使用します WhitelistAspect

  2. アスペクト クラスにカット ポイントを追加します whitelistPointcut()。このカット ポイントの柔軟で構成可能な機能を実現するには、 execution すべてのインターセプトを使用する代わりに、アノテーションを追加します @Whitelist。アノテーション付きメソッドはホワイトリストをチェックします。

  3. アスペクト クラスで Spring の AOP アノテーションを使用して、   Controller メソッドが実行される前にホワイトリストをチェックする@Before 通知メソッド を宣言します。checkWhitelist()

ファセットクラスの擬似コードは次のとおりです。

@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() {

    }

}

@Whitelist 関数を実装するには、Controller メソッドにアノテーションを追加します 。

拡大する

uid() この例では、アノテーションはポイントカットの宣言に使用されており、アノテーション パラメーターを通じて検証されるホワイトリストを実装しました。検証する UID など、後で他のホワイトリストを追加する必要がある場合は、このアノテーションと実装する他のメソッドを追加できます。 カスタム検証。

さらに、Spring の AOP は、 execution(执行方法) 、bean(匹配特定名称的 Bean 对象的执行方法)等しいポイントカット宣言メソッドと @Around(在目标函数执行中执行) 、@After(方法执行后) 等しい通知メソッドもサポートします。

このようにして機能は実現できましたが、リーダーが満足していないのは、プロジェクト内で AOP が多用されすぎているためで、別の方法を提案します。さて、始めなければなりませんでした。

| 方法 2: インターセプターを使用する

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 パラメーターから取得でき、ホワイトリストにあるかどうかを認証の方法として使用できます。認証チェック時になぜそうではないのでしょうか? うーん…血を吐いています。

| 方法 3: ArgumentResolver を使用する

パラメーター パーサーは、カスタム パラメーターを解析するために Spring によって提供されるツールです。よく使用される @RequestParam アノテーションにはその影があります。これを使用すると、コントローラー アクションに入る前にパラメーターを必要なものに組み合わせることができます。

Spring はリクエストを受信 ResolverListすると、カスタム型パラメータ (非基本型) があることを検出し、リゾルバが必要なパラメータを解決できるまでこれらのリゾルバを順番に試します。パラメーター パーサーを実装するには、 HandlerMethodArgumentResolver インターフェイスを実装する必要があります。

成し遂げる

  1. カスタム パラメーター type を定義する AuthParamと、クラス内に appkey 関連のフィールドが存在します。

  2. AuthParamResolver HandlerMethodArgumentResolver インターフェイスを定義し て実装します。

  3. supportsParameter() AuthParam と AuthParamResolver を適応させるためのインターフェイス メソッドを実装します 。

  4. resolveArgument() リクエスト オブジェクトを解析して AuthParam オブジェクトを生成するインターフェイス メソッドを実装し 、ここで AuthParam をチェックしてアプリキーがホワイトリストに含まれているかどうかを確認します。

  5. このリゾルバーを有効にするには、コントローラー アクション メソッドのシグネチャに AuthParam パラメーターを追加します。

実装された 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

| 方法 4: フィルターを使用する

フィルターは Spring によって提供されるものではなく、サーブレット仕様で定義され、サーブレット コンテナーによってサポートされます。Filter によってフィルタリングされたリクエストは Spring コンテナにディスパッチされません。実装も比較的単純で、 javax.servlet.Filter インターフェイスを実装するだけです。

Filter は Spring コンテナ内にないため、Spring コンテナのリソースを取得できず、ネイティブ Java ServletRequest および ServletResponse を使用してリクエスト パラメータを取得することしかできません。

さらに、フィルターでは、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() {
        // 被销毁时调用一次
    }
}

拡大する

フィルターには設定を表示する必要もあります。


@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;
    }
}

| まとめ

4 つの実装にはそれぞれ適切なシナリオがありますが、それらの間の呼び出しシーケンスは何でしょうか?

Filter は Servlet で実装されており、当然最初に呼び出され、後からインターセプタが呼び出され、当然後処理する必要はなく、次にパラメータパーサー、最後にアスペクトの切り口となります。

より魅力的なコンテンツを入手するには、公式アカウント[Programmer Style]に注目してください!

おすすめ

転載: blog.csdn.net/dreaming317/article/details/130120925