В статье представлены четыре способа реализации общей аутентификации в spring-boot, включая традиционный АОП, перехватчик, анализатор параметров и фильтр, а также приведен соответствующий пример кода и, наконец, кратко описан порядок их выполнения.
В последнее время я был завален бесконечными бизнес-требованиями и мне некогда было дышать.Наконец-то я получил работу, которая позволила бы мне вырваться из зоны комфорта кода.Процесс ее решения был очень мучительным, и однажды заставил меня усомниться моя жизнь, но награды были также велики.Очевидно, но я чувствую, что снял слой завесы, которую java, Tomcat, Spring блокировали мои глаза. Их понимание выходит на новый уровень.
Введение
Я давно ничего не выдавал, поэтому для подведения итогов выбрал один аспект, надеясь узнать что-то еще в процессе разбора. Благодаря процветающей экосистеме Java каждому из следующих модулей посвящено большое количество статей. Поэтому я выбрал другой ракурс, отталкиваясь от практических задач, соединив эти разрозненные знания, можно посмотреть на это как на резюме. Для окончательного подробного ознакомления с каждым модулем вы можете обратиться к официальной документации или прочитать другие блоги в Интернете.
Требования очень простые и понятные, и ничуть не отличаются от кокетливых требований, упомянутых продуктами: добавить в наш веб-фреймворк общую функцию проверки белого списка appkey, и надеяться, что она будет более масштабируемой.
Эта веб-инфраструктура представляет собой Spring-Boot на основе Spring-Boot, который основан на Spring-Boot и выполняет некоторые универсальные функции, ориентированные на бизнес, такие как вывод журнала, функциональный переключатель, разрешение общих параметров и т. д. Обычно это прозрачно для бизнеса, я был занят спросом, и код написан, и я никогда не обращаю на это больше внимания.
2. Традиционный АОП
Для этого требования первое, что приходит на ум, это, конечно же, АОП-интерфейс, предоставляемый Spring-boot, нужно только добавить pointcut перед методом Controller, а затем обработать pointcut.
▐ Реализация
Этапы его использования следующие:
-
Используйте @Aspect для объявления класса аспекта WhitelistAspect;
-
Добавим в класс аспекта pointcut whitelistPointcut().Чтобы реализовать гибкую и собираемую способность этого pointcut, здесь мы не используем исполнение для перехвата всего, а добавляем аннотацию @Whitelist, и аннотированный метод будет проверять белый список.
-
Объявите метод уведомления checkWhitelist() в классе аспекта, используя аннотацию Spring AOP @Before, чтобы проверить белый список перед выполнением метода 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() {
}
}
Добавить метод контроллераАннотация @Whitelist реализует эту функциональность.
▐ Развернуть
В этом примере аннотации используются для объявления точек, и я реализовал белый список для проверки с помощью параметров аннотации.Если вам нужно добавить другие белые списки позже, например, проверку по UID, вы можете добавить эту аннотацию к этой аннотации. uid() и другие методы для реализации пользовательской проверки.
Кроме того, АОП Spring также поддерживает методы объявления pointcut, такие как выполнение (метод выполнения), bean-компонент (метод выполнения, который соответствует объекту bean-компонента с определенным именем) и @Around (выполняется при выполнении целевой функции), @After ( после выполнения метода) и т.п. способ оповещения.
Таким образом, функция реализована, но руководитель недоволен =_=, причина в том, что в проекте слишком много используется АОП, причем чрезмерно, предлагаю изменить. Ну просто надо сделать.
3. Перехватчик
Перехватчик Spring (Interceptor) также очень подходит для выполнения этой функции. Как следует из названия, перехватчик используется для определения того, следует ли выполнять этот метод через некоторые параметры до того, как будет выполнено действие в контроллере.Чтобы реализовать перехватчик, вы можете реализовать интерфейс Spring HandlerInterceptor.
▐ Реализация
Этапы реализации следующие:
-
Определите класс перехватчика AppkeyInterceptor и реализуйте интерфейс HandlerInterceptor.
-
Реализуйте его метод preHandle();
-
Судите, необходимо ли перехватить запрос через аннотации и параметры в методе Prehandle, и интерфейс возвращает false при перехвачении запроса;
-
Этот перехват зарегистрирован в пользовательском классе 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, а вайтлист можно использовать как способ Auth, почему бы и нет, когда Auth чек? эммм… рвота кровью.
4. Разрешитель аргументов
Парсер параметров — это инструмент, предоставляемый Spring для разбора пользовательских параметров.Мы часто используем аннотации @RequestParam с его тенью, с его помощью мы можем комбинировать параметры, чтобы совместить внешний вид перед входом в действие контроллера.
Spring будет поддерживать ResolverList.Когда приходит запрос, Spring обнаруживает, что есть параметры пользовательского типа (небазовые типы), и будет пробовать эти Resolver по очереди, пока не будет Resolver, который может разрешить требуемые параметры. Чтобы реализовать преобразователь аргументов, вам необходимо реализовать интерфейс HandlerMethodArgumentResolver.
▐ Реализация
-
Определите тип пользовательского параметра AuthParam, и в классе есть поля, связанные с ключом приложения;
-
Определите AuthParamResolver и реализуйте интерфейс HandlerMethodArgumentResolver;
-
Реализовать метод интерфейса supportsParameter() для адаптации AuthParam и AuthParamResolver;
-
Добиться Resolveargument () Метод интерфейса Аналитическая цена для генерации объекта authparam, и контрольная сумма authParam, проверять AppKEY в белом
-
Добавьте параметр authMamam внутри подписи в методе действий контроллера, чтобы включить этот резолюстр;
Реализованный класс 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();
}
}
j
▐ Развернуть
Разумеется, использование парсера параметров тоже нужно настраивать отдельно, мы его тоже настраиваем в WebMvcConfigurerAdapter:
@Configuration
public class MvcConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthParamResolver());
}
}
После реализации на этот раз я все еще немного волновался, поэтому я поискал в Интернете, есть ли другие способы реализовать эту функцию, и обнаружил, что фильтр является распространенным.
Пять, фильтр
Фильтр не предоставляется Spring, он определен в спецификации сервлета и поддерживается контейнером сервлета. Запросы, отфильтрованные фильтром, не будут отправляться в контейнер Spring. Его реализация также относительно проста, достаточно реализовать интерфейс javax.servlet.Filter.
Поскольку фильтр не получает ресурс контейнера Spring в контейнере Spring, вы можете использовать только собственные Java servletRequest и ServletResponse для получения параметров запроса.
Кроме того, метод 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;
}
}
6. Резюме
У четырех реализаций есть свои подходящие сценарии, так какова последовательность вызовов между ними?
Фильтр реализован сервлетом, который естественно вызывается первым, а перехватывается перехватчик, который вызывается позже, поэтому его не нужно обрабатывать потом, затем парсер параметров и, наконец, точка разреза аспекта.