#11 -- Add user services

This commit is contained in:
Anton Romanov 2025-02-14 19:41:43 +04:00
parent eb0ace5fbe
commit 056ffef87c
13 changed files with 301 additions and 4 deletions

View File

@ -0,0 +1,7 @@
package ru.ulstu.fc.user;
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}

View File

@ -0,0 +1,15 @@
package ru.ulstu.fc.user;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.fc.user.model.User;
public interface UserRepository extends JpaRepository<User, Integer> {
User findOneByLoginIgnoreCase(String login);
@EntityGraph(attributePaths = "roles")
User findOneWithRolesById(int id);
@EntityGraph(attributePaths = "roles")
User findOneWithRolesByLogin(String login);
}

View File

@ -0,0 +1,7 @@
package ru.ulstu.fc.user;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.fc.user.model.UserRole;
public interface UserRoleRepository extends JpaRepository<UserRole, String> {
}

View File

@ -0,0 +1,97 @@
package ru.ulstu.fc.user;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.ulstu.fc.user.model.User;
import ru.ulstu.fc.user.model.UserRole;
import ru.ulstu.fc.user.model.UserRoleConstants;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@Service
@Transactional
public class UserService implements UserDetailsService {
private final Logger log = LoggerFactory.getLogger(UserService.class);
private final PasswordEncoder passwordEncoder;
private final UserRepository userRepository;
private final UserRoleRepository userRoleRepository;
@Value("${admin-password}")
private String adminPassword;
public UserService(PasswordEncoder passwordEncoder,
UserRepository userRepository,
UserRoleRepository userRoleRepository) {
this.passwordEncoder = passwordEncoder;
this.userRepository = userRepository;
this.userRoleRepository = userRoleRepository;
}
public User getUserByLogin(String login) {
return userRepository.findOneByLoginIgnoreCase(login);
}
@Override
public UserDetails loadUserByUsername(String username) {
final User user = userRepository.findOneByLoginIgnoreCase(username);
if (user == null) {
throw new UserNotFoundException(username);
}
return new org.springframework.security.core.userdetails.User(user.getLogin(),
user.getPassword(),
Optional.ofNullable(user.getRoles()).orElse(Collections.emptySet()).stream()
.map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList()));
}
public User createUser(User user) {
if (getUserByLogin(user.getLogin()) != null) {
throw new RuntimeException(user.getLogin());
}
User dbUser = (user.getId() == null)
? user
: getUserById(user.getId());
//user.setRoles(Collections.singleton(new UserRole(UserRoleConstants.USER)));
dbUser.setPassword(passwordEncoder.encode(user.getPassword()));
dbUser.setLogin(user.getLogin());
dbUser = userRepository.save(dbUser);
log.debug("Created Information for User: {}", dbUser.getLogin());
return dbUser;
}
public User getUserById(Integer id) {
return userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found by id"));
}
private void createDefaultUser(String login, String userRole) {
if (getUserByLogin(login) == null) {
UserRole role = userRoleRepository.save(new UserRole(userRole.toString()));
createUser(new User(login, login.equals("admin") ? adminPassword : login, Set.of(role)));
}
}
public void initDefaultAdmin() {
createDefaultUser("admin", UserRoleConstants.ADMIN);
}
public void initDefaultAspirant() {
createDefaultUser("aspirant", UserRoleConstants.ASPIRANT);
}
public void initDefaultManager() {
createDefaultUser("manager", UserRoleConstants.MANAGER);
}
public void initDefaultHead() {
createDefaultUser("head", UserRoleConstants.HEAD);
}
}

View File

@ -0,0 +1,44 @@
package ru.ulstu.fc.user;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import ru.ulstu.fc.config.Constants;
import java.io.IOException;
@Component
public class UserSessionLoginHandler extends SavedRequestAwareAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private final Logger log = LoggerFactory.getLogger(UserSessionLoginHandler.class);
private final UserSessionService userSessionService;
public UserSessionLoginHandler(UserSessionService userSessionService) {
super();
this.userSessionService = userSessionService;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
super.onAuthenticationSuccess(request, response, authentication);
final String login = authentication.getName();
final String ipAddress = IpAddressResolver.getRemoteAddr(request);
final String host = request.getRemoteHost();
log.debug("Authentication Success for {}@{} ({})", login, ipAddress, host);
HttpSession session = request.getSession(false);
if (session != null) {
final String sessionId = session.getId();
userSessionService.createUserSession(sessionId, login, ipAddress, host);
session.setAttribute(Constants.SESSION_ID_ATTR, sessionId);
session.setMaxInactiveInterval(Constants.SESSION_TIMEOUT_SECONDS);
}
}
}

View File

@ -0,0 +1,48 @@
package ru.ulstu.fc.user;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.stereotype.Component;
import ru.ulstu.fc.config.Constants;
import java.io.IOException;
@Component
public class UserSessionLogoutHandler extends SimpleUrlLogoutSuccessHandler implements LogoutSuccessHandler {
private final Logger log = LoggerFactory.getLogger(UserSessionLogoutHandler.class);
private final UserSessionService userSessionService;
public UserSessionLogoutHandler(UserSessionService userSessionService) {
this.userSessionService = userSessionService;
setDefaultTargetUrl(Constants.LOGOUT_URL);
}
@Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
if (authentication == null) {
super.onLogoutSuccess(request, response, authentication);
return;
}
final String login = authentication.getName();
final String ipAddress = IpAddressResolver.getRemoteAddr(request);
final String host = request.getRemoteHost();
log.debug("Logout Success for {}@{} ({})", login, ipAddress, host);
HttpSession session = request.getSession(false);
if (session != null) {
final String sessionId = session.getAttribute(Constants.SESSION_ID_ATTR).toString();
userSessionService.closeUserSession(sessionId);
session.removeAttribute(Constants.SESSION_ID_ATTR);
session.invalidate();
}
super.onLogoutSuccess(request, response, authentication);
}
}

View File

@ -0,0 +1,13 @@
package ru.ulstu.fc.user;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.fc.user.model.UserSession;
import java.util.Date;
import java.util.List;
public interface UserSessionRepository extends JpaRepository<UserSession, Integer> {
UserSession findOneBySessionId(String sessionId);
List<UserSession> findAllByLogoutTimeIsNullAndLoginTimeBefore(Date date);
}

View File

@ -0,0 +1,40 @@
package ru.ulstu.fc.user;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.ulstu.fc.user.model.User;
import ru.ulstu.fc.user.model.UserSession;
@Service
@Transactional
public class UserSessionService {
private final Logger log = LoggerFactory.getLogger(UserSessionService.class);
private final UserSessionRepository userSessionRepository;
private final UserService userService;
public UserSessionService(UserSessionRepository userSessionRepository, UserService userService) {
this.userSessionRepository = userSessionRepository;
this.userService = userService;
}
public void createUserSession(String sessionId, String login, String ipAddress, String host) {
final User user = userService.getUserByLogin(login);
if (user == null) {
throw new UserNotFoundException(login);
}
userSessionRepository.save(new UserSession(sessionId, ipAddress, host, user));
log.debug("User session {} created for user {}@{} ({})", sessionId, login, ipAddress, host);
}
public void closeUserSession(String sessionId) {
final UserSession userSession = userSessionRepository.findOneBySessionId(sessionId);
if (userSession == null) {
throw new IllegalArgumentException(String.format("User session %s not found", sessionId));
}
userSession.close();
userSessionRepository.save(userSession);
log.debug("User session {} closed", sessionId);
}
}

View File

@ -0,0 +1,24 @@
package ru.ulstu.fc.user;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
public class UserUtils {
public static String getCurrentUserLogin() {
final SecurityContext securityContext = SecurityContextHolder.getContext();
if (securityContext == null) {
return null;
}
final Authentication authentication = securityContext.getAuthentication();
if (authentication.getPrincipal() instanceof UserDetails) {
final UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
return springSecurityUser.getUsername();
}
if (authentication.getPrincipal() instanceof String) {
return (String) authentication.getPrincipal();
}
return null;
}
}

View File

@ -1,4 +1,4 @@
package ru.ulstu.fc.core.model;
package ru.ulstu.fc.user.model;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@ -10,6 +10,7 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import ru.ulstu.fc.config.Constants;
import ru.ulstu.fc.core.model.BaseEntity;
import java.util.HashSet;
import java.util.Set;

View File

@ -1,4 +1,4 @@
package ru.ulstu.fc.core.model;
package ru.ulstu.fc.user.model;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;

View File

@ -1,4 +1,4 @@
package ru.ulstu.fc.core.model;
package ru.ulstu.fc.user.model;
public class UserRoleConstants {
public static final String ADMIN = "ROLE_ADMIN";

View File

@ -1,4 +1,4 @@
package ru.ulstu.fc.core.model;
package ru.ulstu.fc.user.model;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@ -8,6 +8,7 @@ import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.validation.constraints.NotNull;
import ru.ulstu.fc.core.model.BaseEntity;
import java.util.Date;