4 способа, которыми Spring Boot реализует универсальную аутентификацию Auth!

В статье представлены четыре способа реализации общей аутентификации в Spring Boot, включая традиционный AOP, перехватчики, анализаторы параметров и фильтры, а также приведены соответствующие примеры кода. Наконец, для справки и изучения кратко изложен порядок их выполнения.

| Предисловие

"В последнее время я был перегружен бесконечными деловыми потребностями, и мне некогда было дышать. Я наконец получил работу, которая позволила мне вырваться из зоны комфорта кода. Процесс ее решения был очень извилистым. Очевидно, но я чувствую, что я стер слой завесы, которую Java, Tomcat и Spring закрывали мои глаза. Достигнут новый уровень понимания их.

Давно не выкладывал, поэтому выбираю один аспект для подведения итогов, надеясь узнать что-то еще в процессе разбора. Благодаря благополучной экологии Java, каждому из следующих модулей посвящено большое количество статей. Поэтому я выбрал другой ракурс, начиная с практических задач, и, соединив эти разрозненные знания воедино, можно посмотреть на них как на резюме. Для максимально подробного ознакомления с каждым модулем вы можете обратиться к официальной документации или прочитать другие блоги в Интернете.

Требования просты и понятны и совсем не совпадают с кокетливыми требованиями, предъявляемыми к продуктам: добавить в наш веб-фреймворк функцию проверки белого списка ключей приложения 通用и надеяться, что его масштабируемость станет лучше.

Этот веб-фреймворк реализован пионерами отдела на основе Spring-Boot. Он находится между бизнесом и фреймворком Spring. Он выполняет некоторые общие функции, ориентированные на бизнес, такие как вывод журнала, переключение функций и общие параметры. анализ. Обычно это прозрачно для бизнеса.В последнее время я был занят составлением требований и хорошим написанием кода, и даже не заметил его существования.

|Метод 1. Традиционный АОП

При выполнении этого требования первое, что приходит на ум, это, конечно же, интерфейс AOP, предоставляемый Spring Boot. Вам нужно только добавить точку отсечения перед методом Controller, а затем обработать точку отсечения.

выполнить

Этапы его использования следующие:

  1. Используйте  @Aspect для объявления класса аспекта  WhitelistAspect;

  2. Добавьте точку отсечения в класс аспекта  whitelistPointcut(). Чтобы реализовать гибкие и настраиваемые возможности этой точки отсечения, вместо использования  execution всех перехватов добавьте аннотацию  @Whitelist, и аннотированный метод будет проверять белый список.

  3. Используйте аннотации AOP Spring в классе аспектов, чтобы объявить  @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() {

    }

}

Добавьте аннотации к методу Controller  @Whitelist для реализации функции.

расширять

В этом примере аннотации используются для объявления pointcut, и я реализовал белый список для проверки с помощью параметров аннотации. Если вам позже понадобится добавить другие белые списки, например UID для проверки, вы можете добавить эту аннотацию и другие методы для  uid() реализации пользовательская проверка.

Кроме того, Spring AOP также поддерживает  execution(执行方法) 、bean(匹配特定名称的 Bean 对象的执行方法)равные методы объявления pointcut и  @Around(在目标函数执行中执行) 、@After(方法执行后) равные методы уведомления.

Таким образом функция реализована, но руководитель не доволен. Причина в том, что АОП в проекте используется слишком много, и он перегружен. Предлагаю другой путь. Ну, мне пришлось это начать.

| Способ 2: использование перехватчика

Перехватчик Spring (Interceptor) также очень подходит для реализации этой функции. Как следует из названия, перехватчик используется для определения того, следует ли выполнять этот метод с помощью некоторых параметров перед выполнением действия в контроллере.Чтобы реализовать перехватчик, вы можете реализовать интерфейс 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, ключ приложения можно получить из параметра Auth, и если он находится в белом списке, его можно использовать как способ аутентификации. почему бы и нет, когда проверка подлинности? эммм... рвота кровью.

| Способ 3: используйте ArgumentResolver

Анализатор параметров — это инструмент, предоставляемый Spring для анализа пользовательских параметров. Наши часто используемые  @RequestParam аннотации имеют свою тень. Используя его, мы можем объединить параметры в то, что мы хотим, прежде чем войти в действие контроллера.

Spring будет поддерживать один  ResolverList. Когда запрос поступит, Spring обнаружит, что существуют параметры пользовательского типа (небазовые типы), и будет пробовать эти Resolvers по очереди, пока Resolver не сможет разрешить требуемые параметры. Чтобы реализовать анализатор параметров, вам необходимо реализовать  HandlerMethodArgumentResolver интерфейс.

выполнить

  1. Определите тип пользовательского параметра  AuthParam, и в классе появятся поля, связанные с ключом приложения;

  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 достаточно реализовать интерфейс.

Поскольку его нет в контейнере Spring, Filter не может получить ресурсы контейнера Spring и может использовать только собственные Java ServletRequest и ServletResponse для получения параметров запроса.

Кроме того, в Filter метод doFilter FilterChain должен вызываться явно, иначе запрос считается перехваченным. Реализуйте что-то вроде:

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

| Резюме

У четырех реализаций есть подходящие сценарии, так какова последовательность вызовов между ними?

Фильтр реализуется сервлетом.Естественно, он вызывается первым, а перехватчик вызывается позже.Естественно, его не нужно обрабатывать потом, потом парсер параметров и, наконец, точку отсечения аспекта.

Чтобы получить больше контента, обратите внимание на официальный аккаунт [Стиль программиста], чтобы получить еще больше интересного контента!

Acho que você gosta

Origin blog.csdn.net/dreaming317/article/details/130120925
Recomendado
Clasificación