Ответы пользователя по тегу Spring
  • Как сделать страницу авторизации?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    В конфигурации нужно включить форм-авторизацию:
    @Configuration
        public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    //твои
                    //настройки
                    .formLogin();
            }
        }
    Ответ написан
    Комментировать
  • Как сделать валидацию данных?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Я на практике использую следующий подход: для каждой хранимой сущности, которую может создать/изменить пользователь, я создаю класс, описывающий форму (иногда бывает, что для редактирования и создания используются даже разные классы в виду разного набора полей).
    Это делается по двум причинам: во-первых - не все поля в хранимой сущности пользователи могут создавать/изменять (например, даты создания/редактирования и идентификаторы), во-вторых - вынесение аннотаций валидации из класса сущности.

    Теперь ближе к делу: для валидации существуют аннотации из пакета javax.validation.constraints, а также дополнительные, предоставляемые реализациями Bean Validation API (например @Email из Hibernate Validator).

    Допустим, у нас есть класс, представляющий собой форму регистрации:
    SignUpForm.java
    public class SignUpForm {
        @Email
        private String email;
    
        @Size(min = 8)
        @Pattern(regexp = "какая-нибудь регулярка для проверки надёжности пароля")
        private String password;
    }


    В контроллере мы будем принимать форму таким образом:
    SignUpController.java
    public class SignUpController {
        public ResponseEntity signUp(@RequestBody @Valid SignUpForm form, BindingResult bindingResult) {
        }
    }



    В form будут содержаться данные, отправленные пользователем, а в bindingResult - результат валидации, который можно легко проверить, вызвав bindingResult.hasErrors(). Отмечу только то, что аргумент класса BindingResult должен быть сразу после аргумента, помеченного аннотациями @RequestBody и valid, в других случаях валидация работать не будет.

    Но дальше - больше. Допустим, нам нужно добавить поле для подтверждения пароля и проверять его соответствие паролю. В таком случае нам надо добавить свою аннотацию (в данном случае на класс) и валидатор.
    Новый класс формы:
    SignUpForm.java
    @PasswordMatch
    public class SignUpForm {
        @Email
        private String email;
    
        @Size(min = 8)
        @Pattern(regexp = "какая-нибудь регулярка для проверки надёжности пароля")
        private String password;
    
        private String passwordConfirmation;
    }


    Аннотация:
    PasswordMatch.java
    @Target({TYPE, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @Constraint(validatedBy = PasswordMatchValidator.class)
    @Documented
    public @interface PasswordMatch {
    
        String message() default "{constraints.passwordmatch}";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    
        @Target({TYPE, ANNOTATION_TYPE})
        @Retention(RUNTIME)
        @Documented
        @interface List {
    
            PasswordMatch[] value();
        }
    }


    Ну и валидатор:
    PasswordMatchValidator.java
    public class PasswordMatchValidator implements ConstraintValidator<PasswordMatch, SignUpForm> {
    
        @Override
        public void initialize(PasswordMatch constraintAnnotation) {
        }
    
        @Override
        public boolean isValid(SignUpForm value, ConstraintValidatorContext context) {
                return Objects.equals(value.getPassword(), value.getPasswordConfirmation());
        }
    }


    И ещё один способ валидации - при помощи спринговых валидаторов. Допустим, нам нужно проверить существование указанного email в нашей БД, что вполне вписывается в процесс валидации. В таком случае пишем валидатор:
    SignUpFormValidator.java
    public class SignUpFormValidator implements Validator {
        public boolean supports(Class<?> type) {
            return SignUpForm.class.isAssignableFrom(type);
        }
        public void validate(Object target, Errors errors) {
            SignUpForm form = (SignUpForm) target;
            // проверяем, что нужно и добавляем ошибки в errors, если они есть
        }
    }


    Регистрируем его в контроллере:
    SignUpController.java
    public class SignupController {
        @InitBinder
        public void initBinder(WebDataBinder binder) {
            binder.addValidators(new SignUpFormValidator());
        }
    }


    После этого Spring будет производить дополнительную валидацию при помощи этого валидатора.

    Более подробно с валидацией в Spring можно почитать в официальной документации.
    Ответ написан
    Комментировать
  • Как организовать правильный маппинг объектов в спринге?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Если в рамках WebMVC, то из контроллера во вьюхи можно и DTO передавать. В обратную сторону (т.е. от клиента при отправке формы) - лучше иметь отдельные классы, представляющие собой набор полей форм (с точки зрения валидации удобнее).
    Если в рамках REST, то есть такой зверь как HATEOAS.
    Ответ написан
    Комментировать
  • Где хранить данные для авторизации?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Сами данные авторизации лучше хранить в файле конфигурации. Оттуда они должны доставаться контекстом приложения и подставляться в свойства класса-клиента API. Как-то так.
    Ответ написан
    Комментировать
  • В каких случаях может потребоваться JNDI?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    JNDI можно использовать для доступа к общим ресурсам, вроде соединений с БД, очередей сообщений, конфигурационных переменных. К примеру, можно в настройках сервера приложений создать соединение с БД, которое будет использоваться несколькими приложениями.
    Однако, сейчас JNDI становится менее популярным инструментом, так как современные приложения разворачиваются в большинстве случае не в серверах приложений. Для распределённой конфигурации сейчас есть такие инструменты, как Spring Cloud Config, Apache Zookeeper, Consul и прочие.
    Ответ написан
    Комментировать
  • Spring: Как сделать аутентификацию на основе bearer токена?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    1. Класс, реализующий Authentication.
      TokenAuthentication.java
      public class TokenAuthentication extends AbstractAuthenticationToken {
          private final Object principal;
          private final Object credentials;
          public TokenAuthentication(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
              super(authorities);
              this.principal = principal;
              this.credentials = credentials;
              this.setAuthenticated(true);
          }
          public TokenAuthentication(Object principal, Object credentials) {
              this(principal, credentials, null);
          }
          @Override
          public Object getPrincipal() {
              return principal;
          }
          @Override
          public Object getCredentials() {
              return credentials;
          }
      }

    2. Фильтр, с которого начнётся процесс аутентификации пользователя. Фильтр должен создать объект типа Authentication и попробовать аутентифицировать его при помощи AuthenticationManager.
      TokenHeaderAuthenticationFilter.java
      public class TokenHeaderAuthenticationFilter extends OncePerRequestFilter {
      
          private final AuthenticationManager authenticationManager;
      
          public TokenHeaderAuthenticationFilter(AuthenticationManager authenticationManager) {
              this.authenticationManager = authenticationManager;
          }
      
          @Override
          protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
              if (SecurityContextHolder.getContext().getAuthentication() != null && SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
                  filterChain.doFilter(servletRequest, servletResponse);
                  return;
              }
              String headerValue = servletRequest.getHeader("X-Authorization");
              if (StringUtils.isEmpty(headerValue)) {
                  filterChain.doFilter(servletRequest, servletResponse);
                  return;
              }
              String token = headerValue.split("\\s")[1];// ну или headerValue.replace("Bearer ")
              TokenAuthentication authenticationToken = new TokenAuthentication(null, token);
              authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(servletRequest));
      
              Authentication authenticationResult = authenticationManager.authenticate(authenticationToken);
              SecurityContextHolder.getContext().setAuthentication(authenticationResult);
              filterChain.doFilter(servletRequest, servletResponse);
          }
      }

    3. Класс, реализующий AuthenticationProvider. Этот класс и будет производить аутентификацию полученных данных.
      TokenAuthenticationProvider.java
      public class TokenAuthenticationProvider implements AuthenticationProvider {
          @Override
          public boolean supports(Class<?> authentication) {
              return TokenAuthentication.class.isAssignableFrom(authentication);
          }
          @Override
          public Authentication authenticate(Authentication authentication) throws AuthenticationException {
              // здесь должна быть реализована логика аутентификации полученных данных
          }
      }

    4. Последний штрих - конфигурация.
      SecurityConfig.java
      @Configuration
      public class SecurityConfig extends WebSecurityConfigurerAdapter {
      
          @Bean
          public AuthenticationProvider tokenAuthenticationProvider() {
              return new TokenAuthenticationProvider();
          }
      
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http.addFilterAfter(new TokenHeaderAuthenticationFilter(authenticationManagerBean()), BasicAuthenticationFilter.class)
                      .authenticationProvider(tokenAuthenticationProvider())
                      .authorizeRequests()
                      .anyRequest().authenticated();
          }
      }

    Ответ написан
    Комментировать
  • Java EE умер, есть ли смысл делать на нем проекты?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Стоит ли сейчас разрабатывать web-проекты с использованием Java EE

    Вполне себе стоит, если душа не лежит к Spring или не позволяет корпоративная этика

    насколько я понял его пустили в свободное плавание на github

    Такое себе "свободное" плавание. ИМХО, выход из-под крыла Oracle только в плюс пойдёт.

    Насколько зависим Spring от Java EE ?

    Spring Web зависит от Servlet API, может использовать в качестве отображений JSP, а также интегрирован с JSF. Spring Data JPA, как видно из названия, основан на JPA. Есть возможность использования JMS. И т.д. в целом, т.е. Spring очень тесно связан с Java EE
    Ответ написан
    2 комментария
  • Spring Boot + Html5 video. Как показывать видео, которые расположены в другой директории системы?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Конфигурацией:
    @Configuration
    public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/video/**").addResourceLocations("/path/to/video");
        }
    }


    Таким образом по адресу localhost:8080/video/kotiki.mp4 будет доступно видео /path/to/video/kotiki.mp4 на файловой системе (пример для *nix)
    Ответ написан
    Комментировать
  • Актуальны ли еще JSP в Spring MVC проектах?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Каждому своё, никто не запрещает использовать JSP/JSPX, но разработчики Spring рекомендуют использовать что-нибудь более современное, вроде Apache FreeMarker или Thymeleaf.
    Ответ написан
    3 комментария
  • Не работает тест для контроллера, в чем проблема?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Судя по логам, контроллер у тебя не создаётся или не регистрируется. Можно для верности в Before проверять наличие в контексте бинов класса Controller.
    Ответ написан
    1 комментарий
  • Spring Security несколько различных авторизаций. Как реализовать?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Для каждого механизма авторизации описываешь свой класс конфигурации, наследуемый от WebSecurityConfigurerAdapter, и добавляешь классам конфигурации аннотацию @Order с порядковым номером. Таким образом Spring Security будет при запросе обходить конфигурации и проверять их применимость к запросу.

    Так же можно сузить применимость механизма авторизации при помощи фильтрующего метода http.antMatcher() (не путать с antMatchers(), который используется для настроек доступа).
    Ответ написан
    Комментировать
  • Первоначальная настройка Spring MVC. Как настроить?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Ответ написан
    Комментировать
  • Правильная логика будет сайта и возможно ли это??

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Реализовать, то что ты описал можно, но это - абсолютно неправильный подход.
    Авторизацию и аутентификацию лучше реализовывать при помощи Spring Security. Так же колдовать с сессиями нет никакого смысла - Spring WebMVC всё это умеет. Если нужны какие-то более тонкие настройки управления сессиями, то можно поковырять Spring Session (что нужно в 0,001% случаев).
    Прежде чем что-то самостоятельно реализовывать, почитай документацию, так как подавляющее большинство задач и проблем уже давно решены стандартными средствами.
    Ответ написан
    Комментировать
  • Не работает mongodb в spring, как исправить??

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Судя по ошибке, у тебя проблема заключается в использовании зависимостей, несовместимых друг с другом. Указанный метод появился в Spring Core версии 4.2.
    Ответ написан
  • Если разница в spring между Spring boot и Spring framework??

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Spring Framework - собственно, фреймворк, на котором основана вся экосистема Spring.IO (Framework, Data, Security и прочие проекты). Он может использоваться как самостоятельно, так и в связке с другими проектами.

    Spring Boot предоставляет готовые конфигурации компонентов, минимизируя время, затрачиваемое на конфигурирование.

    Плюс Spring Boot при помощи Maven-плагина позволяет собирать приложения в виде "толстых JAR", в которые собираются все зависимости. Так же есть возможность JAR делать исполняемым.
    Ответ написан
  • Как ограничить права юзера?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Описанное тобой поведение и есть правильное. 403 ошибка будет выдаваться, если профиль пользователя попробует просмотреть пользователь, у которого нет ни роли USER, ни роли ADMIN.
    Ответ написан
    Комментировать
  • Что использовать openId или oauth??

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Если тебе нужна только аутентификация от стороннего провайдера с минимальным набором данных о пользователе, то хватит openID, если же тебе нужно со своего сайта обращаться к ресурсам сторонних провайдеров (запрашивать фотографии, список друзей и т.д.), то здесь уже нужен OAuth.

    Если в кратце, то и openID и OAuth предоставляют возможность реализовать аутентификацию в своём приложении используя сторонних провайдеров, но OAuth предоставляет больше возможностей.
    Ответ написан
    Комментировать
  • Как записать json в mongodb?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    В MongoDB данные и так хранятся в (B)JSON, в примере, ссылку на который ты дал, всё вкратце рассказано. Или ты хочешь добиться чего-то иного?
    Ответ написан
    Комментировать
  • Spring Data как правильно настроить/сохранить entity?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    rp = reportPeriodRepository.save(rp);

    И будет тебе счастье. Но лучше создавать пустую коллекцию в get-методе при необходимости. А вообще, лучше отказаться от обращения к @OneToMany и @ManyToMany коллекциям.
    Ответ написан
    Комментировать
  • Как заменить одну реализацию другой в списке однотипных бинов?

    jaxtr
    @jaxtr
    JavaEE/Spring-разработчик
    Для этого существует аннотация @Conditional. Если используется Spring Boot, то у него есть @ConditionalOnMissingClass, которая позволяет указать, что отмеченный компонент нужно создавать, если не найден указанный класс:
    @ConditionalOnMissingClass(ThirdBean.class)
    @Component
    public class FirstBean implements SimpleBean {
        @Override
        public String getName() {
            return "First Bean";
        }
    }
    Ответ написан
    1 комментарий