1. Обзор
В этом уроке – мы заменим процесс аутентификации OAuth2, поддерживаемый Reddit, более простым логином на основе формы .
Мы все равно сможем подключить Reddit к приложению после входа в систему, мы просто не будем использовать Reddit для управления нашим основным потоком входа.
2. Базовая Регистрация Пользователя
Во-первых, давайте заменим старый поток аутентификации.
2.1. Сущность Пользователя
Мы внесем несколько изменений в сущность пользователя: сделаем имя пользователя уникальным, добавим пароль поле (временное):
@Entity public class User { ... @Column(nullable = false, unique = true) private String username; private String password; ... }
2.2. Зарегистрировать Нового Пользователя
Далее – давайте посмотрим, как зарегистрировать нового пользователя в бэкэнде:
@Controller @RequestMapping(value = "/user") public class UserController { @Autowired private UserService service; @RequestMapping(value = "/register", method = RequestMethod.POST) @ResponseStatus(HttpStatus.OK) public void register( @RequestParam("username") String username, @RequestParam("email") String email, @RequestParam("password") String password) { service.registerNewUser(username, email, password); } }
Очевидно, что это базовая операция создания для пользователя – никаких наворотов.
Вот фактическая реализация на уровне сервиса :
@Service public class UserService { @Autowired private UserRepository userRepository; @Autowired private PreferenceRepository preferenceReopsitory; @Autowired private PasswordEncoder passwordEncoder; @Override public void registerNewUser(String username, String email, String password) { User existingUser = userRepository.findByUsername(username); if (existingUser != null) { throw new UsernameAlreadyExistsException("Username already exists"); } User user = new User(); user.setUsername(username); user.setPassword(passwordEncoder.encode(password)); Preference pref = new Preference(); pref.setTimezone(TimeZone.getDefault().getID()); pref.setEmail(email); preferenceReopsitory.save(pref); user.setPreference(pref); userRepository.save(user); } }
2.3. Работа С Исключениями
И простое Исключение UserAlreadyExistsException :
public class UsernameAlreadyExistsException extends RuntimeException { public UsernameAlreadyExistsException(String message) { super(message); } public UsernameAlreadyExistsException(String message, Throwable cause) { super(message, cause); } }
Исключение обрабатывается в основном обработчике исключений приложения :
@ExceptionHandler({ UsernameAlreadyExistsException.class }) public ResponseEntity
2.4. Простая Страница Регистрации
Наконец – то-простой интерфейс signup.html :
Стоит еще раз отметить, что это не полностью зрелый процесс регистрации – просто очень быстрый процесс. Для получения полной информации о процессе регистрации вы можете ознакомиться с основной серией регистраций здесь, на сайте Baeldung.
3. Новая Страница Входа в Систему
Вот наша новая и простая страница входа в систему :
Sign upInvalid username or password
4. Конфигурация системы Безопасности
Теперь – давайте взглянем на новую конфигурацию безопасности :
@Configuration @EnableWebSecurity @ComponentScan({ "org.baeldung.security" }) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyUserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(encoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http ... .formLogin() .loginPage("/") .loginProcessingUrl("/j_spring_security_check") .defaultSuccessUrl("/home") .failureUrl("/?error=true") .usernameParameter("username") .passwordParameter("password") ... } @Bean public PasswordEncoder encoder() { return new BCryptPasswordEncoder(11); } }
Большинство вещей довольно просты, поэтому мы не будем подробно останавливаться на них здесь.
И вот обычай UserDetailsService :
@Service public class MyUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) { User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException(username); } return new UserPrincipal(user); } }
И вот наш пользовательский Принципал ” Принципал пользователя” , который реализует Учетные записи пользователей :
public class UserPrincipal implements UserDetails { private User user; public UserPrincipal(User user) { super(); this.user = user; } @Override public String getUsername() { return user.getUsername(); } @Override public String getPassword() { return user.getPassword(); } @Override public Collection extends GrantedAuthority> getAuthorities() { return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
Примечание: Мы использовали наш пользовательский Принципал ” UserPrincipal” вместо Spring Security по умолчанию Пользователь .
5. Аутентифицируйте Reddit
Теперь, когда мы больше не полагаемся на Reddit для нашего потока аутентификации, нам нужно разрешить пользователям подключать свои учетные записи к Reddit после входа в систему.
Во – первых, нам нужно изменить старую логику входа в Reddit:
@RequestMapping("/redditLogin") public String redditLogin() { OAuth2AccessToken token = redditTemplate.getAccessToken(); service.connectReddit(redditTemplate.needsCaptcha(), token); return "redirect:home"; }
И фактическая реализация – метод connectReddit() :
@Override public void connectReddit(boolean needsCaptcha, OAuth2AccessToken token) { UserPrincipal userPrincipal = (UserPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); User currentUser = userPrincipal.getUser(); currentUser.setNeedCaptcha(needsCaptcha); currentUser.setAccessToken(token.getValue()); currentUser.setRefreshToken(token.getRefreshToken().getValue()); currentUser.setTokenExpiration(token.getExpiration()); userRepository.save(currentUser); }
Обратите внимание, как логика reddit Login() теперь используется для подключения учетной записи пользователя в нашей системе к его учетной записи Reddit путем получения Доступа пользователя .
Что касается интерфейса – это довольно просто:
Welcome, Bob
Connect your Account to Reddit
Нам также необходимо убедиться, что пользователи подключают свои учетные записи к Reddit, прежде чем пытаться отправлять сообщения:
@RequestMapping("/post") public String showSubmissionForm(Model model) { if (getCurrentUser().getAccessToken() == null) { model.addAttribute("msg", "Sorry, You did not connect your account to Reddit yet"); return "submissionResponse"; } ... }
6. Заключение
Небольшое приложение reddit определенно продвигается вперед.
Старый поток аутентификации, полностью поддерживаемый Reddit, вызывал некоторые проблемы. Итак, теперь у нас есть чистый и простой логин на основе формы , при этом вы все еще можете подключить свой API Reddit в задней части.
Хорошая штука.