ホームページ  >  記事  >  Java  >  SpringBoot が ThreadLocal を介してログイン インターセプトを実装する方法

SpringBoot が ThreadLocal を介してログイン インターセプトを実装する方法

WBOY
WBOY転載
2023-05-22 12:04:421310ブラウズ

    1 はじめに

    日々の開発において登録とログインは最も一般的なことと言えますが、一般的に入社後はこのような機能が備わっています。新しいプロジェクトでない限り、開発は完了しています。ここ 2 日間で、PC 側で登録とログイン機能を完了する必要に遭遇しました。

    そのような要件を達成するには、多くの方法があります。

    1) HandlerInterceptor WebMvcConfigurer ThreadLocal

    2) Filter filter

    3) Security Framework Kiri (軽量フレームワーク)

    4) セキュリティ フレームワーク Spring Securety (重量フレームワーク)

    そして、最初の Spring HandlerInterceptor WebMvcConfigurer ThreadLocal テクノロジを使用して実装します。

    2 具象クラス

    2.1HandlerInterceptor

    HandlerInterceptor は springMVC のインターセプタに提供されるインターフェースで、サーブレット開発におけるフィルター Filter に似ており、サーブレット開発における前処理に使用されます。処理と後処理では、3 つのメソッドを書き直す必要があります。

    preHandle:

    呼び出し時刻: コントローラーのメソッド処理前

    実行順序: 連鎖インターセプターの場合、宣言順にインターセプターが次々に実行されます

    false が返された場合、実行は中断されます 注: afterCompletion には入りません

    postHandle:

    呼び出し前提: preHandle は true を返します

    呼び出し時間:Controller メソッドの処理後、DispatcherServlet ビューを描画する前、つまりこのメソッド内で ModelAndView を操作できます

    実行順序:Chained Interceptor の場合、Intercepter の順序で実行されます。宣言の.

    備考: postHandle は post で始まりますが、post リクエストと get リクエストの両方を処理できます

    afterCompletion:

    呼び出し前提: preHandle は true を返します

    呼び出し時間: DispatcherServlet がビューをレンダリングした後

    主にリソースをクリーンアップするために使用されます

    2.2WebMvcConfigurer

    WebMvcConfigurer 構成クラスは実際には の内部構成メソッドですSpring、代わりに JavaBean の形式を使用 従来の xml 構成ファイル形式はフレームワーク用にカスタマイズされており、一部のハンドラー、インターセプター、ビューリゾルバー、およびメッセージコンバーターはカスタマイズできます。 Java ベースのメソッドに基づく Spring Mvc 構成の場合、構成クラスを作成し、WebMvcConfigurer

    インターフェイスを実装する必要があります。Spring Boot 1.5 バージョンの

    は、WebMvcConfigurerAdapter のメソッドを書き換えて追加することに依存しています。カスタムインターセプトコンバーター、メッセージコンバーターなど。 SpringBoot 2.0 バージョン以降、このクラスは @Deprecated (非推奨) とマークされています。公式の推奨事項は、WebMvcConfigurer を直接実装するか、WebMvcConfigurationSupport を直接継承することです。最初の方法は WebMvcConfigurer インターフェイスを実装することであり (推奨)、2 番目の方法は WebMvcConfigurationSupport クラスを継承することです

    #3 コードの練習

    1) HandlerInterceptor を継承するようにインターセプター HeadTokenInterceptor を作成します

    package com.liubujun.config;
    import com.liubujun.moudle.UserToken;
    import com.liubujun.util.SecurityContextUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.http.HttpStatus;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.xml.ws.handler.Handler;
    import java.io.IOException;
    /**
     * @Author: liubujun
     * @Date: 2022/5/21 16:12
     */
    @Component
    @Slf4j
    public class HeadTokenInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String authorization = request.getHeader("Authorization");
            if (authorization == null ) {
                unauthorized(response);
                return false;
            }
            //这里一般都会解析出userToken的值,这里为了方便就直接new了
            UserToken userToken  = new UserToken();
            SecurityContextUtil.addUser(userToken);
            return false;
        }
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        }
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            SecurityContextUtil.removeUser();
        }
        private void unauthorized(HttpServletResponse response) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            try {
                response.getWriter().append(HttpStatus.UNAUTHORIZED.getReasonPhrase());
            } catch (IOException e) {
                log.error("HttpServletResponse writer error.msg",HttpStatus.UNAUTHORIZED.getReasonPhrase());
                log.error(e.getMessage(),e);
            }
        }
    }

    2) WebMvcConfigurationSupportを継承するように MyWebMvcConfigurer を作成します

    package com.liubujun.config;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import java.util.ArrayList;
    /**
     * @Author: liubujun
     * @Date: 2022/5/21 16:40
     */
    @Configuration
    public class MyWebMvcConfigurer extends WebMvcConfigurationSupport {
        @Autowired
        private HeadTokenInterceptor headTokenInterceptor;
        /**
         * 类似于白名单,在这边添加的请求不会走拦截器
         * @param registry
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            ArrayList<String> pattres = new ArrayList<>();
            pattres.add("/login/login");
            registry.addInterceptor(headTokenInterceptor).excludePathPatterns(pattres).addPathPatterns("/**");
            super.addInterceptors(registry);
        }
        /**
         * 添加静态资源
         * @param registry
         */
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("xxx.html")
                    .addResourceLocations("classpath:/META-INF/resources");
            super.addResourceHandlers(registry);
        }
    }

    3) ユーザー情報を格納する ThreadLocal クラスを作成します

    package com.liubujun.util;
    import com.liubujun.moudle.UserToken;
    import org.springframework.core.NamedThreadLocal;
    /**
     * @Author: liubujun
     * @Date: 2022/5/23 9:41
     */
    public class SecurityContextUtil {
        private static ThreadLocal<UserToken> threadLocal = new NamedThreadLocal<>("user");
        public static void addUser(UserToken user){
            threadLocal.set(user);
        }
        public static UserToken getUser(){
            return threadLocal.get();
        }
        public static void removeUser(){
            threadLocal.remove();
        }
        public static String getPhoneNumber(){
            return threadLocal.get().getPhoneNumber();
        }
        public static Integer getId(){
            return threadLocal.get().getId();
        }
        public static String getUserText(){
            return threadLocal.get().getUserText();
        }
    }

    4) テスト コントローラーを作成します

    @RestController
    @RequestMapping(value = "/login",produces = {"application/json;charset=UTF-8"})
    public class Login {
        @PostMapping("/login")
        public String login(){
            return "登录请求不需要拦截";
        }
        @PostMapping("/other")
        public String other(){
            return "其他的请求需要拦截";
        }
    }

    5) テスト

    ログイン インターフェイスをテストします (トークンを渡さずに直接実行します)

    SpringBoot が ThreadLocal を介してログイン インターセプトを実装する方法

    他のインターフェイスをテストします。トークンが渡されない場合はインターセプトされます

    SpringBoot が ThreadLocal を介してログイン インターセプトを実装する方法#

    以上がSpringBoot が ThreadLocal を介してログイン インターセプトを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。