login form okie
This commit is contained in:
+44
@@ -0,0 +1,44 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver;
|
||||
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CustomOAuth2AuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver {
|
||||
|
||||
private final OAuth2AuthorizationRequestResolver defaultResolver;
|
||||
|
||||
public CustomOAuth2AuthorizationRequestResolver(ClientRegistrationRepository clientRegistrationRepository, String authorizationRequestBaseUri) {
|
||||
this.defaultResolver = new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, authorizationRequestBaseUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
|
||||
OAuth2AuthorizationRequest req = defaultResolver.resolve(request);
|
||||
return customizeAuthorizationRequest(req);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) {
|
||||
OAuth2AuthorizationRequest req = defaultResolver.resolve(request, clientRegistrationId);
|
||||
return customizeAuthorizationRequest(req);
|
||||
}
|
||||
|
||||
private OAuth2AuthorizationRequest customizeAuthorizationRequest(OAuth2AuthorizationRequest req) {
|
||||
if (req == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, Object> additionalParameters = new LinkedHashMap<>(req.getAdditionalParameters());
|
||||
additionalParameters.put("prompt", "select_account");
|
||||
|
||||
return OAuth2AuthorizationRequest.from(req)
|
||||
.additionalParameters(additionalParameters)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.sisvietnamvn.web.config;
|
||||
|
||||
import com.sisvietnamvn.web.domain.Authority;
|
||||
import com.sisvietnamvn.web.repository.AuthorityRepository;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class RoleSeeder implements CommandLineRunner {
|
||||
|
||||
private final AuthorityRepository authorityRepository;
|
||||
|
||||
public RoleSeeder(AuthorityRepository authorityRepository) {
|
||||
this.authorityRepository = authorityRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
List<String> roles = Arrays.asList(
|
||||
AuthoritiesConstants.EDITOR,
|
||||
AuthoritiesConstants.AUTHOR,
|
||||
AuthoritiesConstants.CONTRIBUTOR,
|
||||
AuthoritiesConstants.SUBSCRIBER,
|
||||
AuthoritiesConstants.PRE_AUTH_2FA
|
||||
);
|
||||
|
||||
for (String roleName : roles) {
|
||||
if (authorityRepository.findById(roleName).isEmpty()) {
|
||||
Authority authority = new Authority();
|
||||
authority.setName(roleName);
|
||||
authorityRepository.save(authority);
|
||||
System.out.println("Seeded role: " + roleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
-9
@@ -3,6 +3,7 @@ package com.sisvietnamvn.web.config;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
|
||||
import com.sisvietnamvn.web.security.*;
|
||||
import com.sisvietnamvn.web.security.oauth2.CustomOidcUserService;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
@@ -19,6 +20,10 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||
import tech.jhipster.config.JHipsterConstants;
|
||||
import tech.jhipster.config.JHipsterProperties;
|
||||
|
||||
import com.sisvietnamvn.web.security.CustomAuthenticationSuccessHandler;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter;
|
||||
|
||||
@Configuration
|
||||
@EnableMethodSecurity(securedEnabled = true)
|
||||
public class SecurityConfiguration {
|
||||
@@ -26,10 +31,14 @@ public class SecurityConfiguration {
|
||||
private final Environment env;
|
||||
|
||||
private final JHipsterProperties jHipsterProperties;
|
||||
private final CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
|
||||
private final ClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
public SecurityConfiguration(Environment env, JHipsterProperties jHipsterProperties) {
|
||||
public SecurityConfiguration(Environment env, JHipsterProperties jHipsterProperties, CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler, ClientRegistrationRepository clientRegistrationRepository) {
|
||||
this.env = env;
|
||||
this.jHipsterProperties = jHipsterProperties;
|
||||
this.customAuthenticationSuccessHandler = customAuthenticationSuccessHandler;
|
||||
this.clientRegistrationRepository = clientRegistrationRepository;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -38,18 +47,18 @@ public class SecurityConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) {
|
||||
public SecurityFilterChain filterChain(HttpSecurity http, CustomOidcUserService customOidcUserService) {
|
||||
http.cors(withDefaults())
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.csrf(withDefaults())
|
||||
.authorizeHttpRequests(authz ->
|
||||
// prettier-ignore
|
||||
authz
|
||||
.requestMatchers(HttpMethod.GET, "/", "/about", "/flex-finish", "/tin-tuc", "/tin-tuc/**", "/lien-he",
|
||||
"/manage/**", "/css/**", "/images/**", "/js/**", "/UMass*/**", "/Undergraduate*/**",
|
||||
"/manage/login", "/css/**", "/images/**", "/js/**", "/vendor/**", "/fonts/**", "/login-assets/**", "/UMass*/**", "/Undergraduate*/**",
|
||||
"/favicon.ico", "/favicons/**", "/flex-finish/**", "/contact-us/**", "/uploads/**", "/api/manage/snippets/**", "/page/**", "/news/article/**", "/post/**", "/error",
|
||||
"/about-us", "/specialty", "/doctor", "/service", "/health-library", "/news-and-events", "/patient-support", "/medical-expert", "/umcers", "/bidding", "/contact-us")
|
||||
.permitAll()
|
||||
.requestMatchers(HttpMethod.POST, "/manage/**", "/api/manage/media/upload").permitAll()
|
||||
.requestMatchers(HttpMethod.POST, "/api/manage/media/upload").permitAll()
|
||||
.requestMatchers(HttpMethod.GET, "/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
||||
.requestMatchers(HttpMethod.POST, "/api/authenticate").permitAll()
|
||||
.requestMatchers(HttpMethod.GET, "/api/authenticate").permitAll()
|
||||
@@ -63,11 +72,30 @@ public class SecurityConfiguration {
|
||||
.requestMatchers("/management/health/**").permitAll()
|
||||
.requestMatchers("/management/info").permitAll()
|
||||
.requestMatchers("/management/prometheus").permitAll()
|
||||
.requestMatchers("/2fa/**").hasAuthority(AuthoritiesConstants.PRE_AUTH_2FA)
|
||||
.requestMatchers("/manage/**").hasAnyAuthority(AuthoritiesConstants.ADMIN, AuthoritiesConstants.EDITOR, AuthoritiesConstants.AUTHOR, AuthoritiesConstants.CONTRIBUTOR, AuthoritiesConstants.SUBSCRIBER, AuthoritiesConstants.USER)
|
||||
.requestMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN))
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.exceptionHandling(exceptions -> exceptions
|
||||
.authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
|
||||
.accessDeniedHandler(new BearerTokenAccessDeniedHandler()))
|
||||
.formLogin(form -> form
|
||||
.loginPage("/manage/login")
|
||||
.successHandler(customAuthenticationSuccessHandler)
|
||||
.permitAll()
|
||||
)
|
||||
.logout(logout -> logout
|
||||
.logoutUrl("/manage/logout")
|
||||
.logoutSuccessUrl("/manage/login?logout")
|
||||
.permitAll()
|
||||
)
|
||||
.oauth2Login(oauth2 -> oauth2
|
||||
.loginPage("/manage/login")
|
||||
.successHandler(customAuthenticationSuccessHandler)
|
||||
.authorizationEndpoint(authorization -> authorization
|
||||
.authorizationRequestResolver(new CustomOAuth2AuthorizationRequestResolver(clientRegistrationRepository, OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI))
|
||||
)
|
||||
.userInfoEndpoint(userInfo -> userInfo
|
||||
.oidcUserService(customOidcUserService)
|
||||
)
|
||||
)
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED))
|
||||
.oauth2ResourceServer(oauth2 -> oauth2.jwt(withDefaults()));
|
||||
if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT))) {
|
||||
http.authorizeHttpRequests(authz -> authz.requestMatchers("/h2-console/**").permitAll())
|
||||
|
||||
@@ -7,10 +7,6 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
public class HomeController {
|
||||
|
||||
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "index";
|
||||
}
|
||||
|
||||
// Trang Flex Finish (MỚI THÊM)
|
||||
@GetMapping("/flex-finish")
|
||||
|
||||
@@ -46,6 +46,11 @@ public class PageController {
|
||||
return renderPage(pageService.findBySlug(slug), model);
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String getHome(Model model) {
|
||||
return renderPage(pageService.findByPageType(com.sisvietnamvn.web.domain.PageType.HOME), model);
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/about-us")
|
||||
public String getAboutUs(Model model) { return renderPage(pageService.findByPageType(com.sisvietnamvn.web.domain.PageType.ABOUT_US), model); }
|
||||
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
package com.sisvietnamvn.web.controller;
|
||||
|
||||
import com.sisvietnamvn.web.domain.Authority;
|
||||
import com.sisvietnamvn.web.domain.User;
|
||||
import com.sisvietnamvn.web.repository.UserRepository;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
import com.sisvietnamvn.web.security.DomainUserDetailsService;
|
||||
import dev.samstevens.totp.code.CodeGenerator;
|
||||
import dev.samstevens.totp.code.CodeVerifier;
|
||||
import dev.samstevens.totp.code.DefaultCodeGenerator;
|
||||
import dev.samstevens.totp.code.DefaultCodeVerifier;
|
||||
import dev.samstevens.totp.exceptions.QrGenerationException;
|
||||
import dev.samstevens.totp.qr.QrData;
|
||||
import dev.samstevens.totp.qr.QrGenerator;
|
||||
import dev.samstevens.totp.qr.ZxingPngQrGenerator;
|
||||
import dev.samstevens.totp.secret.DefaultSecretGenerator;
|
||||
import dev.samstevens.totp.secret.SecretGenerator;
|
||||
import dev.samstevens.totp.time.SystemTimeProvider;
|
||||
import dev.samstevens.totp.time.TimeProvider;
|
||||
import dev.samstevens.totp.util.Utils;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/2fa")
|
||||
public class TwoFactorController {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public TwoFactorController(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String show2FaForm(Authentication authentication) {
|
||||
if (authentication == null || !authentication.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals(AuthoritiesConstants.PRE_AUTH_2FA))) {
|
||||
return "redirect:/manage/login";
|
||||
}
|
||||
|
||||
String username = authentication.getName();
|
||||
Optional<User> userOpt = userRepository.findOneByLogin(username);
|
||||
|
||||
if (userOpt.isPresent()) {
|
||||
User user = userOpt.get();
|
||||
if (!user.isUsing2FA()) {
|
||||
return "redirect:/2fa/setup";
|
||||
}
|
||||
}
|
||||
|
||||
return "manage/2fa/verify";
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public String verify2Fa(@RequestParam("code") String code, Authentication authentication, RedirectAttributes redirectAttributes) {
|
||||
String username = authentication.getName();
|
||||
Optional<User> userOpt = userRepository.findOneWithAuthoritiesByLogin(username);
|
||||
|
||||
if (userOpt.isEmpty()) {
|
||||
return "redirect:/manage/login";
|
||||
}
|
||||
|
||||
User user = userOpt.get();
|
||||
if (verifyCode(user.getTotpSecret(), code)) {
|
||||
upgradeSecurityContext(user, authentication);
|
||||
return "redirect:/manage";
|
||||
} else {
|
||||
redirectAttributes.addFlashAttribute("errorMessage", "Invalid 2FA code. Please try again.");
|
||||
return "redirect:/2fa";
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/setup")
|
||||
public String showSetupForm(Authentication authentication, Model model) {
|
||||
String username = authentication.getName();
|
||||
Optional<User> userOpt = userRepository.findOneByLogin(username);
|
||||
|
||||
if (userOpt.isEmpty()) {
|
||||
return "redirect:/manage/login";
|
||||
}
|
||||
|
||||
User user = userOpt.get();
|
||||
if (user.isUsing2FA()) {
|
||||
return "redirect:/2fa";
|
||||
}
|
||||
|
||||
if (user.getTotpSecret() == null) {
|
||||
SecretGenerator secretGenerator = new DefaultSecretGenerator();
|
||||
user.setTotpSecret(secretGenerator.generate());
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
try {
|
||||
QrData data = new QrData.Builder()
|
||||
.label(user.getEmail() != null ? user.getEmail() : user.getLogin())
|
||||
.secret(user.getTotpSecret())
|
||||
.issuer("SIS Vietnam")
|
||||
.algorithm(dev.samstevens.totp.code.HashingAlgorithm.SHA1)
|
||||
.digits(6)
|
||||
.period(30)
|
||||
.build();
|
||||
|
||||
QrGenerator generator = new ZxingPngQrGenerator();
|
||||
byte[] imageData = generator.generate(data);
|
||||
String mimeType = generator.getImageMimeType();
|
||||
String dataUri = Utils.getDataUriForImage(imageData, mimeType);
|
||||
|
||||
model.addAttribute("qrCode", dataUri);
|
||||
model.addAttribute("secret", user.getTotpSecret());
|
||||
} catch (QrGenerationException e) {
|
||||
model.addAttribute("errorMessage", "Failed to generate QR Code.");
|
||||
}
|
||||
|
||||
return "manage/2fa/setup";
|
||||
}
|
||||
|
||||
@PostMapping("/setup")
|
||||
public String verifySetup(@RequestParam("code") String code, Authentication authentication, RedirectAttributes redirectAttributes) {
|
||||
String username = authentication.getName();
|
||||
Optional<User> userOpt = userRepository.findOneWithAuthoritiesByLogin(username);
|
||||
|
||||
if (userOpt.isEmpty()) {
|
||||
return "redirect:/manage/login";
|
||||
}
|
||||
|
||||
User user = userOpt.get();
|
||||
if (verifyCode(user.getTotpSecret(), code)) {
|
||||
user.setUsing2FA(true);
|
||||
userRepository.save(user);
|
||||
upgradeSecurityContext(user, authentication);
|
||||
return "redirect:/manage";
|
||||
} else {
|
||||
redirectAttributes.addFlashAttribute("errorMessage", "Invalid 2FA code. Please try again.");
|
||||
return "redirect:/2fa/setup";
|
||||
}
|
||||
}
|
||||
|
||||
private boolean verifyCode(String secret, String code) {
|
||||
TimeProvider timeProvider = new SystemTimeProvider();
|
||||
CodeGenerator codeGenerator = new DefaultCodeGenerator();
|
||||
CodeVerifier verifier = new DefaultCodeVerifier(codeGenerator, timeProvider);
|
||||
return verifier.isValidCode(secret, code);
|
||||
}
|
||||
|
||||
private void upgradeSecurityContext(User user, Authentication originalAuthentication) {
|
||||
List<GrantedAuthority> authorities = user.getAuthorities().stream()
|
||||
.map(Authority::getName)
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
DomainUserDetailsService.UserWithId userWithId = new DomainUserDetailsService.UserWithId(
|
||||
user.getLogin(),
|
||||
user.getPassword(),
|
||||
authorities,
|
||||
user.getId()
|
||||
);
|
||||
|
||||
UsernamePasswordAuthenticationToken newAuth = new UsernamePasswordAuthenticationToken(
|
||||
userWithId, originalAuthentication.getCredentials(), authorities);
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(newAuth);
|
||||
}
|
||||
}
|
||||
+3
@@ -12,6 +12,8 @@ import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
|
||||
/**
|
||||
* Controller for managing post Categories in the admin panel.
|
||||
@@ -19,6 +21,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/manage/posts/categories")
|
||||
@PreAuthorize("hasAnyAuthority(\"" + AuthoritiesConstants.ADMIN + "\", \"" + AuthoritiesConstants.EDITOR + "\")")
|
||||
public class ManageCategoryController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ManageCategoryController.class);
|
||||
|
||||
+4
-1
@@ -1,8 +1,10 @@
|
||||
package com.sisvietnamvn.web.controller.manage;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
|
||||
/**
|
||||
* Controller for the admin dashboard index page.
|
||||
@@ -10,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/manage")
|
||||
@PreAuthorize("hasAnyAuthority(\"" + AuthoritiesConstants.ADMIN + "\", \"" + AuthoritiesConstants.EDITOR + "\", \"" + AuthoritiesConstants.AUTHOR + "\", \"" + AuthoritiesConstants.CONTRIBUTOR + "\", \"" + AuthoritiesConstants.SUBSCRIBER + "\", \"" + AuthoritiesConstants.USER + "\")")
|
||||
public class ManageDashboardController {
|
||||
|
||||
@GetMapping({"", "/"})
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.sisvietnamvn.web.controller.manage;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
* Controller for the admin login page.
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/manage/login")
|
||||
public class ManageLoginController {
|
||||
|
||||
@GetMapping
|
||||
public String login() {
|
||||
return "manage/login";
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -13,13 +13,15 @@ import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
/**
|
||||
* Controller for managing CMS Pages in the admin panel.
|
||||
* Provides CRUD operations for static pages.
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/manage/pages")
|
||||
@PreAuthorize("hasAnyAuthority(\"" + AuthoritiesConstants.ADMIN + "\", \"" + AuthoritiesConstants.EDITOR + "\")")
|
||||
public class ManagePageController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ManagePageController.class);
|
||||
@@ -62,6 +64,7 @@ public class ManagePageController {
|
||||
model.addAttribute("page", page);
|
||||
model.addAttribute("statuses", PageStatus.values());
|
||||
model.addAttribute("pageTypes", com.sisvietnamvn.web.domain.PageType.values());
|
||||
model.addAttribute("layouts", com.sisvietnamvn.web.domain.PageLayout.values());
|
||||
model.addAttribute("isNew", true);
|
||||
return "manage/pages/form";
|
||||
}
|
||||
@@ -78,6 +81,7 @@ public class ManagePageController {
|
||||
if (bindingResult.hasErrors()) {
|
||||
model.addAttribute("statuses", PageStatus.values());
|
||||
model.addAttribute("pageTypes", com.sisvietnamvn.web.domain.PageType.values());
|
||||
model.addAttribute("layouts", com.sisvietnamvn.web.domain.PageLayout.values());
|
||||
model.addAttribute("isNew", true);
|
||||
return "manage/pages/form";
|
||||
}
|
||||
@@ -100,6 +104,7 @@ public class ManagePageController {
|
||||
model.addAttribute("page", pageOptional.get());
|
||||
model.addAttribute("statuses", PageStatus.values());
|
||||
model.addAttribute("pageTypes", com.sisvietnamvn.web.domain.PageType.values());
|
||||
model.addAttribute("layouts", com.sisvietnamvn.web.domain.PageLayout.values());
|
||||
model.addAttribute("isNew", false);
|
||||
return "manage/pages/form";
|
||||
}
|
||||
@@ -117,6 +122,7 @@ public class ManagePageController {
|
||||
if (bindingResult.hasErrors()) {
|
||||
model.addAttribute("statuses", PageStatus.values());
|
||||
model.addAttribute("pageTypes", com.sisvietnamvn.web.domain.PageType.values());
|
||||
model.addAttribute("layouts", com.sisvietnamvn.web.domain.PageLayout.values());
|
||||
model.addAttribute("isNew", false);
|
||||
return "manage/pages/form";
|
||||
}
|
||||
|
||||
+3
@@ -18,6 +18,8 @@ import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
|
||||
/**
|
||||
* Controller for managing blog Posts in the admin panel.
|
||||
@@ -25,6 +27,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/manage/posts")
|
||||
@PreAuthorize("hasAnyAuthority(\"" + AuthoritiesConstants.ADMIN + "\", \"" + AuthoritiesConstants.EDITOR + "\", \"" + AuthoritiesConstants.AUTHOR + "\", \"" + AuthoritiesConstants.CONTRIBUTOR + "\")")
|
||||
public class ManagePostController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ManagePostController.class);
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package com.sisvietnamvn.web.controller.manage;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import com.sisvietnamvn.web.domain.User;
|
||||
import com.sisvietnamvn.web.hook.HookManager;
|
||||
import com.sisvietnamvn.web.service.UserService;
|
||||
import com.sisvietnamvn.web.service.dto.AdminUserDTO;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
/**
|
||||
* Controller for managing the logged-in User's Profile in the admin panel.
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/manage/profile")
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
public class ManageProfileController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ManageProfileController.class);
|
||||
|
||||
private final UserService userService;
|
||||
private final HookManager hookManager;
|
||||
|
||||
public ManageProfileController(UserService userService, HookManager hookManager) {
|
||||
this.userService = userService;
|
||||
this.hookManager = hookManager;
|
||||
}
|
||||
|
||||
@ModelAttribute
|
||||
public void adminInit() {
|
||||
hookManager.doAction("admin_init");
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /manage/profile : view the current user's profile form.
|
||||
*/
|
||||
@GetMapping
|
||||
public String showProfileForm(Model model, RedirectAttributes redirectAttributes) {
|
||||
LOG.debug("Request to show profile form");
|
||||
Optional<User> userOptional = userService.getUserWithAuthorities();
|
||||
if (userOptional.isEmpty()) {
|
||||
redirectAttributes.addFlashAttribute("errorMessage", "User session not found.");
|
||||
return "redirect:/manage";
|
||||
}
|
||||
|
||||
model.addAttribute("userDTO", new AdminUserDTO(userOptional.get()));
|
||||
return "manage/users/profile";
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /manage/profile/update : update basic information for the current user.
|
||||
*/
|
||||
@PostMapping("/update")
|
||||
public String updateProfile(@Valid @ModelAttribute("userDTO") AdminUserDTO userDTO,
|
||||
BindingResult bindingResult,
|
||||
Model model,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
LOG.debug("Request to update current user Profile : {}", userDTO);
|
||||
if (bindingResult.hasErrors()) {
|
||||
return "manage/users/profile";
|
||||
}
|
||||
|
||||
try {
|
||||
userService.updateUser(userDTO.getFirstName(), userDTO.getLastName(), userDTO.getEmail(), userDTO.getLangKey(), userDTO.getImageUrl());
|
||||
redirectAttributes.addFlashAttribute("successMessage", "Profile updated successfully!");
|
||||
} catch (Exception e) {
|
||||
redirectAttributes.addFlashAttribute("errorMessage", "Error updating profile: " + e.getMessage());
|
||||
}
|
||||
|
||||
return "redirect:/manage/profile";
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /manage/profile/password : change the current user's password.
|
||||
*/
|
||||
@PostMapping("/password")
|
||||
public String changePassword(@RequestParam("currentPassword") String currentPassword,
|
||||
@RequestParam("newPassword") String newPassword,
|
||||
@RequestParam("confirmPassword") String confirmPassword,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
LOG.debug("Request to change password for current user");
|
||||
|
||||
if (!newPassword.equals(confirmPassword)) {
|
||||
redirectAttributes.addFlashAttribute("errorPasswordMessage", "New password and confirm password do not match!");
|
||||
return "redirect:/manage/profile";
|
||||
}
|
||||
|
||||
try {
|
||||
userService.changePassword(currentPassword, newPassword);
|
||||
redirectAttributes.addFlashAttribute("successPasswordMessage", "Password changed successfully!");
|
||||
} catch (Exception e) {
|
||||
redirectAttributes.addFlashAttribute("errorPasswordMessage", "Incorrect current password or error changing password.");
|
||||
}
|
||||
|
||||
return "redirect:/manage/profile";
|
||||
}
|
||||
}
|
||||
+3
@@ -12,6 +12,8 @@ import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
|
||||
/**
|
||||
* Controller for managing post Tags in the admin panel.
|
||||
@@ -19,6 +21,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/manage/posts/tags")
|
||||
@PreAuthorize("hasAnyAuthority(\"" + AuthoritiesConstants.ADMIN + "\", \"" + AuthoritiesConstants.EDITOR + "\", \"" + AuthoritiesConstants.AUTHOR + "\")")
|
||||
public class ManageTagController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ManageTagController.class);
|
||||
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
package com.sisvietnamvn.web.controller.manage;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import com.sisvietnamvn.web.config.Constants;
|
||||
import com.sisvietnamvn.web.domain.User;
|
||||
import com.sisvietnamvn.web.hook.HookManager;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
import com.sisvietnamvn.web.service.UserService;
|
||||
import com.sisvietnamvn.web.service.dto.AdminUserDTO;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
/**
|
||||
* Controller for managing Users in the admin panel.
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/manage/users")
|
||||
@PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
|
||||
public class ManageUserController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ManageUserController.class);
|
||||
|
||||
private final UserService userService;
|
||||
private final HookManager hookManager;
|
||||
|
||||
public ManageUserController(UserService userService, HookManager hookManager) {
|
||||
this.userService = userService;
|
||||
this.hookManager = hookManager;
|
||||
}
|
||||
|
||||
@ModelAttribute
|
||||
public void adminInit() {
|
||||
hookManager.doAction("admin_init");
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /manage/users : get all users.
|
||||
*/
|
||||
@GetMapping
|
||||
public String listUsers(@PageableDefault(size = 20, sort = "login") Pageable pageable, Model model) {
|
||||
LOG.debug("REST request to get all User for an admin");
|
||||
Page<AdminUserDTO> page = userService.getAllManagedUsers(pageable);
|
||||
model.addAttribute("users", page.getContent());
|
||||
model.addAttribute("page", page);
|
||||
return "manage/users/list";
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /manage/users/new : show create form.
|
||||
*/
|
||||
@GetMapping("/new")
|
||||
public String showCreateForm(Model model) {
|
||||
LOG.debug("Request to show create user form");
|
||||
AdminUserDTO userDTO = new AdminUserDTO();
|
||||
userDTO.setLangKey(Constants.DEFAULT_LANGUAGE);
|
||||
model.addAttribute("userDTO", userDTO);
|
||||
model.addAttribute("authorities", userService.getAuthorities());
|
||||
model.addAttribute("isNew", true);
|
||||
return "manage/users/form";
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /manage/users : create a new user.
|
||||
*/
|
||||
@PostMapping
|
||||
public String createUser(@Valid @ModelAttribute("userDTO") AdminUserDTO userDTO,
|
||||
BindingResult bindingResult,
|
||||
Model model,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
LOG.debug("Request to create User : {}", userDTO);
|
||||
|
||||
if (bindingResult.hasErrors()) {
|
||||
model.addAttribute("authorities", userService.getAuthorities());
|
||||
model.addAttribute("isNew", true);
|
||||
return "manage/users/form";
|
||||
}
|
||||
|
||||
if (userDTO.getId() != null) {
|
||||
redirectAttributes.addFlashAttribute("errorMessage", "A new user cannot already have an ID");
|
||||
return "redirect:/manage/users/new";
|
||||
}
|
||||
|
||||
// Ensure email login constraint (optional depending on jhipster config, but good practice)
|
||||
if (userDTO.getLogin() != null) {
|
||||
userDTO.setLogin(userDTO.getLogin().toLowerCase());
|
||||
}
|
||||
|
||||
try {
|
||||
User newUser = userService.createUser(userDTO);
|
||||
redirectAttributes.addFlashAttribute("successMessage", "User created successfully! Login: " + newUser.getLogin());
|
||||
} catch (Exception e) {
|
||||
redirectAttributes.addFlashAttribute("errorMessage", "Error creating user: " + e.getMessage());
|
||||
return "redirect:/manage/users/new";
|
||||
}
|
||||
|
||||
return "redirect:/manage/users";
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /manage/users/{login}/edit : show edit form.
|
||||
*/
|
||||
@GetMapping("/{login}/edit")
|
||||
public String showEditForm(@PathVariable String login, Model model, RedirectAttributes redirectAttributes) {
|
||||
LOG.debug("Request to show edit form for User : {}", login);
|
||||
Optional<User> userOptional = userService.getUserWithAuthoritiesByLogin(login);
|
||||
if (userOptional.isEmpty()) {
|
||||
redirectAttributes.addFlashAttribute("errorMessage", "User not found.");
|
||||
return "redirect:/manage/users";
|
||||
}
|
||||
|
||||
model.addAttribute("userDTO", new AdminUserDTO(userOptional.get()));
|
||||
model.addAttribute("authorities", userService.getAuthorities());
|
||||
model.addAttribute("isNew", false);
|
||||
return "manage/users/form";
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /manage/users/{login} : update a user.
|
||||
*/
|
||||
@PostMapping("/{login}")
|
||||
public String updateUser(@PathVariable String login,
|
||||
@Valid @ModelAttribute("userDTO") AdminUserDTO userDTO,
|
||||
BindingResult bindingResult,
|
||||
Model model,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
LOG.debug("Request to update User : {}", userDTO);
|
||||
if (bindingResult.hasErrors()) {
|
||||
model.addAttribute("authorities", userService.getAuthorities());
|
||||
model.addAttribute("isNew", false);
|
||||
return "manage/users/form";
|
||||
}
|
||||
|
||||
Optional<User> existingUser = userService.getUserWithAuthoritiesByLogin(login);
|
||||
if (existingUser.isEmpty()) {
|
||||
redirectAttributes.addFlashAttribute("errorMessage", "User not found.");
|
||||
return "redirect:/manage/users";
|
||||
}
|
||||
|
||||
userDTO.setId(existingUser.get().getId());
|
||||
|
||||
try {
|
||||
userService.updateUser(userDTO);
|
||||
redirectAttributes.addFlashAttribute("successMessage", "User updated successfully!");
|
||||
} catch (Exception e) {
|
||||
redirectAttributes.addFlashAttribute("errorMessage", "Error updating user: " + e.getMessage());
|
||||
return "redirect:/manage/users/" + login + "/edit";
|
||||
}
|
||||
|
||||
return "redirect:/manage/users";
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /manage/users/{login}/delete : delete a user.
|
||||
*/
|
||||
@PostMapping("/{login}/delete")
|
||||
public String deleteUser(@PathVariable String login, RedirectAttributes redirectAttributes) {
|
||||
LOG.debug("Request to delete User : {}", login);
|
||||
userService.deleteUser(login);
|
||||
redirectAttributes.addFlashAttribute("successMessage", "User deleted successfully!");
|
||||
return "redirect:/manage/users";
|
||||
}
|
||||
}
|
||||
+3
@@ -15,9 +15,12 @@ import java.nio.file.StandardCopyOption;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/manage/media")
|
||||
@PreAuthorize("hasAnyAuthority(\"" + AuthoritiesConstants.ADMIN + "\", \"" + AuthoritiesConstants.EDITOR + "\", \"" + AuthoritiesConstants.AUTHOR + "\", \"" + AuthoritiesConstants.CONTRIBUTOR + "\")")
|
||||
public class MediaController {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MediaController.class);
|
||||
|
||||
+3
@@ -10,12 +10,15 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import com.sisvietnamvn.web.security.AuthoritiesConstants;
|
||||
|
||||
/**
|
||||
* REST controller for fetching predefined HTML snippets to be previewed in Editor.js.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/manage/snippets")
|
||||
@PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
|
||||
public class SnippetController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SnippetController.class);
|
||||
|
||||
@@ -53,6 +53,11 @@ public class Page extends AbstractAuditingEntity<Long> {
|
||||
@Column(name = "display_order")
|
||||
private Integer displayOrder = 0;
|
||||
|
||||
@NotNull
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "layout", length = 20, nullable = false)
|
||||
private PageLayout layout = PageLayout.STANDARD;
|
||||
|
||||
// --- Getters and Setters ---
|
||||
|
||||
@Override
|
||||
@@ -120,6 +125,14 @@ public class Page extends AbstractAuditingEntity<Long> {
|
||||
this.displayOrder = displayOrder;
|
||||
}
|
||||
|
||||
public PageLayout getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
public void setLayout(PageLayout layout) {
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
// --- equals, hashCode, toString ---
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.sisvietnamvn.web.domain;
|
||||
|
||||
/**
|
||||
* Enumeration for Page Layout options.
|
||||
*/
|
||||
public enum PageLayout {
|
||||
STANDARD,
|
||||
SIDEBAR,
|
||||
FULL_WIDTH
|
||||
}
|
||||
@@ -85,6 +85,12 @@ public class User extends AbstractAuditingEntity<Long> implements Serializable {
|
||||
@Column(name = "reset_date")
|
||||
private Instant resetDate = null;
|
||||
|
||||
@Column(name = "using_2fa", nullable = false)
|
||||
private boolean using2FA = false;
|
||||
|
||||
@Column(name = "totp_secret")
|
||||
private String totpSecret;
|
||||
|
||||
@JsonIgnore
|
||||
@ManyToMany
|
||||
@JoinTable(
|
||||
@@ -185,6 +191,22 @@ public class User extends AbstractAuditingEntity<Long> implements Serializable {
|
||||
this.resetDate = resetDate;
|
||||
}
|
||||
|
||||
public boolean isUsing2FA() {
|
||||
return using2FA;
|
||||
}
|
||||
|
||||
public void setUsing2FA(boolean using2FA) {
|
||||
this.using2FA = using2FA;
|
||||
}
|
||||
|
||||
public String getTotpSecret() {
|
||||
return totpSecret;
|
||||
}
|
||||
|
||||
public void setTotpSecret(String totpSecret) {
|
||||
this.totpSecret = totpSecret;
|
||||
}
|
||||
|
||||
public String getLangKey() {
|
||||
return langKey;
|
||||
}
|
||||
|
||||
+10
@@ -7,9 +7,19 @@ public final class AuthoritiesConstants {
|
||||
|
||||
public static final String ADMIN = "ROLE_ADMIN";
|
||||
|
||||
public static final String EDITOR = "ROLE_EDITOR";
|
||||
|
||||
public static final String AUTHOR = "ROLE_AUTHOR";
|
||||
|
||||
public static final String CONTRIBUTOR = "ROLE_CONTRIBUTOR";
|
||||
|
||||
public static final String SUBSCRIBER = "ROLE_SUBSCRIBER";
|
||||
|
||||
public static final String USER = "ROLE_USER";
|
||||
|
||||
public static final String ANONYMOUS = "ROLE_ANONYMOUS";
|
||||
|
||||
public static final String PRE_AUTH_2FA = "ROLE_PRE_AUTH_2FA";
|
||||
|
||||
private AuthoritiesConstants() {}
|
||||
}
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.sisvietnamvn.web.security;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.web.DefaultRedirectStrategy;
|
||||
import org.springframework.security.web.RedirectStrategy;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
@Component
|
||||
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
|
||||
|
||||
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
||||
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
|
||||
|
||||
boolean isPreAuth = authorities.stream()
|
||||
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(AuthoritiesConstants.PRE_AUTH_2FA));
|
||||
|
||||
if (isPreAuth) {
|
||||
redirectStrategy.sendRedirect(request, response, "/2fa");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isWordPressRole = authorities.stream()
|
||||
.anyMatch(grantedAuthority -> {
|
||||
String role = grantedAuthority.getAuthority();
|
||||
return role.equals(AuthoritiesConstants.ADMIN) ||
|
||||
role.equals(AuthoritiesConstants.EDITOR) ||
|
||||
role.equals(AuthoritiesConstants.AUTHOR) ||
|
||||
role.equals(AuthoritiesConstants.CONTRIBUTOR) ||
|
||||
role.equals(AuthoritiesConstants.SUBSCRIBER) ||
|
||||
role.equals(AuthoritiesConstants.USER);
|
||||
});
|
||||
|
||||
if (isWordPressRole) {
|
||||
redirectStrategy.sendRedirect(request, response, "/manage");
|
||||
} else {
|
||||
redirectStrategy.sendRedirect(request, response, "/");
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -79,10 +79,12 @@ public class DomainUserDetailsService implements UserDetailsService {
|
||||
}
|
||||
|
||||
public static UserWithId fromUser(User user) {
|
||||
List<GrantedAuthority> grantedAuthorities = Collections.singletonList(new SimpleGrantedAuthority(AuthoritiesConstants.PRE_AUTH_2FA));
|
||||
|
||||
return new UserWithId(
|
||||
user.getLogin(),
|
||||
user.getPassword(),
|
||||
user.getAuthorities().stream().map(Authority::getName).map(SimpleGrantedAuthority::new).toList(),
|
||||
grantedAuthorities,
|
||||
user.getId()
|
||||
);
|
||||
}
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.sisvietnamvn.web.security.oauth2;
|
||||
|
||||
import com.sisvietnamvn.web.domain.Authority;
|
||||
import com.sisvietnamvn.web.domain.User;
|
||||
import com.sisvietnamvn.web.repository.UserRepository;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class CustomOidcUserService extends OidcUserService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public CustomOidcUserService(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
|
||||
OidcUser oidcUser = super.loadUser(userRequest);
|
||||
String email = oidcUser.getEmail();
|
||||
|
||||
System.out.println("===============================");
|
||||
System.out.println("CustomOidcUserService is called!");
|
||||
System.out.println("Google Email: " + email);
|
||||
System.out.println("===============================");
|
||||
|
||||
if (email == null) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error("invalid_token", "Email not found from OAuth2 provider", ""));
|
||||
}
|
||||
|
||||
// Map the Google email to an existing User in the database (Option A)
|
||||
Optional<User> userOptional = userRepository.findOneWithAuthoritiesByEmailIgnoreCase(email);
|
||||
|
||||
if (userOptional.isEmpty()) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error("user_not_found", "User not found in system. Please contact administrator.", ""));
|
||||
}
|
||||
|
||||
User user = userOptional.get();
|
||||
|
||||
if (!user.isActivated()) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error("user_not_activated", "User is not activated.", ""));
|
||||
}
|
||||
|
||||
List<GrantedAuthority> authorities = user.getAuthorities().stream()
|
||||
.map(Authority::getName)
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new DefaultOidcUser(authorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user