{"id":13889,"url":"\/distributions\/13889\/click?bit=1&hash=1ca9d3af68367c3851a48783eb73a779f640773356888dee19fed6204e72a9d7","title":"\u00ab\u0410\u0432\u0438\u0442\u043e\u00bb \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0443 \u0441\u043a\u0438\u0434\u043e\u043a \u043d\u0430 \u043d\u0435\u0434\u0432\u0438\u0436\u0438\u043c\u043e\u0441\u0442\u044c","buttonText":"","imageUuid":"","isPaidAndBannersEnabled":false}

Полное руководство по аутентификации с помощью токена Jwt на Java

В данной статье мы поговорим о том, как реализовать аутентификацию с помощью токена Jwt на Java.

Предварительные условия:Базовые знания о том, как взаимодействует клиент-сервер, цикл запрос-ответ.

В этой статье я собираюсь предоставить потрясающее руководство по работе с Authentication Manager на Java.

Итак, первый вопрос, который может возникнуть в процессе, заключается в том,что такое Authentication Manager?

Authentication Manager является фундаментальной основой для процесса аутентификации Spring security. AuthenticationManager - это API, который определяет, как должны работать фильтры Spring Security.

Относительные зависимости, которые нам нужны для интеграции аутентификации с Spring boot:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> </dependency>

Структура папок для безопасности System будет выглядеть следующим образом :

controller - Предоставляет обработчики для любого входящего запроса.

RequestFormat - Спецификаторы формата поля данных для входа в систему, запроса на регистрацию.

ResponseFormat - Ответы на запросы аутентификации на стороне сервера.

Security

Models

Repository

SecurityServices

Давайте создадим файл User.java в Package :Models:

import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "auser") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(unique = true) private String username; @Column(unique = true) private String email; private String password; public User(String username, String email, String password) { this.username = username; this.email = email; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public User() { super(); } }

Давайте сопоставим созданный выше класс модели с репозиторием для работы с JpaRepository (JPA= Java Persistence API ) :

import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import com.artisticlubfab.AuthMS.models.User; public interface UserRepository extends JpaRepository<User, String> { Optional<User> findByUsername(String username); Boolean existsByUsername(String username); Boolean existsByEmail(String email); }

Теперь мы создадим 2 файла UserDetailsServiceImpl.java и UserDetailsService.java, которые будут выполнять все операции, связанные с пользователем.

/** Important points : UserDetailsService comes from spring security core library */ @Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired UserRepository userRepository; @Override @Transactional public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException ("user Not Found with username: " + username)); return UserDetailsImpl.build(user); } } //UserDetailsImpl.java /** The above class while returning the built UserDetails Object uses the below referred code */ public class UserDetailsImpl implements UserDetails { /** this class uses UserDetails Interface which is available in spring security core library */ private static final long serialVersionUID = 1L; private Long id; private String username; private String email; @JsonIgnore private String password; public UserDetailsImpl(Long id, String username, String email, String password) { this.id = id; this.username = username; this.email = email; this.password = password; } public static UserDetailsImpl build(User user) { return new UserDetailsImpl(user.getId(), user.getUsername(), user.getEmail(), user.getPassword()); } public Long getId() { return id; } public String getEmail() { return email; } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; UserDetailsImpl user = (UserDetailsImpl) o; return Objects.equals(id, user.id); } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } }

Теперь, когда мы уже готовы с основной функциональной частью, мы можем перейти к работе с Controller и частями Request,Response Format.

Для целей обучения мы создадим 2 отдельных Controller-файла:

1. AuthController.java

2. UserController.java

Конечные точки, которые мы будем предоставлять в AuthController, не должны быть отключены ни для какого разрешения. Но для того, чтобы UserController выполнял любой запрос и извлекал данные, он должен запрашивать учётные данные для аутентификации.

Итак, если вы внимательно следили, мы определили свойства маршрутизации в файле SecurityConfig. В нём указано, что конечная точка всегда должна быть разрешена, поскольку для входа в приложение пользователь должен пройти процесс аутентификации, верно? Таким образом, шаблон (/api/auth/**) должен быть разрешён для любого суффиксного дерева. Но для api / test, который специфичен для UserController, он всегда должен быть аутентифицирован, поскольку это то, где мы на самом деле будем пытаться извлечь или обновить любые данные, относящиеся к пользователю.

.authorizeRequests() .antMatchers("/api/auth/**") .permitAll() .antMatchers("/api/test/**") .permitAll().anyRequest().authenticated();

Теперь давайте подготовим Request ,Response formats.Создайте 2 файла внутри пакета RequestFormat:

1. LoginRequest.java

2. SignUpRequest.java

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

//LoginRequest.java public class LoginRequest { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } --------------------------------------------------------------------------- //SignUpRequest.java public class SignupRequest { private String username; private String email; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }

Таким же образом у нас будет DTO и для Response Formats. Создайте эти файлы внутри ResponseFormats:

//JwtReponse.java /** this file will return us the operated user object and the token associated with it after successful login attempt. */ public class JwtResponse { private String token; private String type = "Bearer"; private Long id; private String username; private String email; public JwtResponse(String accessToken, Long id, String username, String email) { this.token = accessToken; this.id = id; this.username = username; this.email = email; } // ADD GETTERS AND SETTERS HERE } ------------------------------------------------------------------------------- //MessageReponse.java public class MessageResponse { private String message; public MessageResponse(String message) { this.message = message; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }

AuthController.java

Он будет обрабатывать все конечные точки api тестирования, которые выполняют операции, специфичные для пользователя.Он использует JwtUtils и PasswordEncoder. PasswordEncoder помогает нам хранить пароль, закодированный с помощью стандартизированного механизма. @ CrossOrigin указывает совместное использование ресурсов из разных источников и в нём указано, что любой входящий запрос из любого источника не должен блокироваться.

UserController.Java

Здесь мы не выполняем никаких специальных операций. Мы просто хотим ограничить маршрут, чтобы он был доступен только в том случае, если пользователь успешно прошёл аутентификацию

//UserController.java @CrossOrigin(origins = "*", maxAge = 4800) @RestController @RequestMapping("/api/test") public class UserController { @GetMapping("/all") public MessageResponse allAccess() { return new MessageResponse("Server is up....."); } @GetMapping("/greeting") @PreAuthorize("isAuthenticated()") public MessageResponse userAccess() { return new MessageResponse ("Congratulations! You are an authenticated user."); } } ---------------------------------------------------------------------------- //AuthController.java @CrossOrigin(origins = "*", maxAge = 3600) @RestController @RequestMapping("/api/auth") public class AuthController { @Autowired AuthenticationManager authenticationManager; @Autowired UserRepository userRepository; @Autowired PasswordEncoder encoder; @Autowired JwtUtils jwtUtils; @PostMapping("/signin") public ResponseEntity<?> authenticateuser (@RequestBody LoginRequest loginRequest) { org.springframework.security.core.Authentication authentication = authenticationManager.authenticate (new UsernamePasswordAuthenticationToken (loginRequest.getUsername(), loginRequest.getPassword())); SecurityContextHolder.getContext() .setAuthentication(authentication); String jwt = jwtUtils.generateJwtToken(authentication); UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); return ResponseEntity .ok(new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(), userDetails.getEmail())); } @PostMapping("/signup") public ResponseEntity<?> registerUser (@RequestBody SignupRequest signUpRequest) { if (userRepository.existsByUsername(signUpRequest .getUsername())) { return ResponseEntity.badRequest() .body(new MessageResponse ("Error: username is already taken!")); } if (userRepository.existsByEmail (signUpRequest.getEmail())) { return ResponseEntity.badRequest() .body(new MessageResponse ("Error: Email is already in use!")); } // Create new user account User user = new User(signUpRequest.getUsername(), signUpRequest.getEmail(), encoder.encode(signUpRequest.getPassword())); userRepository.save(user); return ResponseEntity .ok(new MessageResponse("user registered successfully!")); } }

Итак, всё!Теперь вы готовы протестировать данную технологию! Если вы всё будете делать шаг за шагом, у вас должно получиться!

Статья была взята из этого иисточника:

0
Комментарии
Читать все 0 комментариев
null