在我当前的项目中,我有两个单独的实体。
我很困惑我们如何通过Spring Security为两个单独的实体管理同一项目中的登录过程?
截至目前,它与一个User实体合作,现在我必须在Customer表的帮助下为客户集成另一个登录。
有可能吗?
我正在共享一些代码以获取更多权限。
private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class);
private final UserLoginRepository userRepository;
public DomainUserDetailsService(UserLoginRepository userRepository) {
this.userRepository = userRepository;
}
@Override
@Transactional
public UserDetails loadUserByUsername(final String login) {
log.debug("Authenticating {}", login);
if (new EmailValidator().isValid(login, null)) {
Optional<User> userByEmailFromDatabase = userRepository.findOneWithAuthoritiesByLogin(login);
return userByEmailFromDatabase.map(user -> createSpringSecurityUser(login, user))
.orElseThrow(() -> new UsernameNotFoundException("User with email " + login + " was not found in the database"));
}
String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
Optional<User> userByLoginFromDatabase = userRepository.findOneWithAuthoritiesByLogin(lowercaseLogin);
return userByLoginFromDatabase.map(user -> createSpringSecurityUser(lowercaseLogin, user))
.orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the database"));
}
private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) {
List<GrantedAuthority> grantedAuthorities = user.getAuthorities().stream()
.map(authority -> new SimpleGrantedAuthority(authority.getName()))
.collect(Collectors.toList());
return new org.springframework.security.core.userdetails.User(user.getLogin(),
user.getPassword(),
grantedAuthorities);
}
}
private final AuthenticationManagerBuilder authenticationManagerBuilder;
private final UserDetailsService userDetailsService;
private final TokenProvider tokenProvider;
private final CorsFilter corsFilter;
private final SecurityProblemSupport problemSupport;
public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, UserDetailsService userDetailsService,TokenProvider tokenProvider,CorsFilter corsFilter, SecurityProblemSupport problemSupport) {
this.authenticationManagerBuilder = authenticationManagerBuilder;
this.userDetailsService = userDetailsService;
this.tokenProvider = tokenProvider;
this.corsFilter = corsFilter;
this.problemSupport = problemSupport;
}
@PostConstruct
public void init() {
try {
authenticationManagerBuilder
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
} catch (Exception e) {
throw new BeanInitializationException("Security configuration failed", e);
}
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/app/**/*.{js,html}")
.antMatchers("/i18n/**")
.antMatchers("/content/**")
.antMatchers("/swagger-ui/index.html");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.csrf()
.disable()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/register").permitAll()
.antMatchers("/api/activate").permitAll()
.antMatchers("/api/userLogin").permitAll()
.antMatchers("/api/account/reset-password/init").permitAll()
.antMatchers("/api/account/reset-password/finish").permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/management/health").permitAll()
.antMatchers("/management/info").permitAll()
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/v2/api-docs/**").permitAll()
.antMatchers("/swagger-resources/configuration/ui").permitAll()
.antMatchers("/swagger-ui/index.html").hasAuthority(AuthoritiesConstants.ADMIN)
.and()
.apply(securityConfigurerAdapter());
}
private JWTConfigurer securityConfigurerAdapter() {
return new JWTConfigurer(tokenProvider);
}
}
@PostMapping("/userLogin")
@Timed
public Response<JWTToken> authorize(
@Valid @RequestBody UserLoginReq userLoginReq) {
Map<String, Object> responseData = null;
try {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userLoginReq.getUsername(), userLoginReq.getPassword());
Authentication authentication = this.authenticationManager
.authenticate(authenticationToken);
SecurityContextHolder.getContext()
.setAuthentication(authentication);
}
答案 0 :(得分:1)
起初客户也是用户,不是吗?因此,也许更简单的解决方案是同时以用户身份创建客户(使用某些flag / db字段usertype ={USER|CUSTOMER|...}
)。如果您仍然需要管理两个实体,那么您的方法是正确的,但是在DetailService中,只需实现另一个方法即可读取客户实体,然后创建spring的User。
答案 1 :(得分:0)
是的,您可以通过userName
组合用户类型,并用如下字符分隔:
示例:
String userName=inputUserName +":APP_USER";
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userName, password);
UserDetailsService.loadUserByUsername(userName)
中的
首先拆分得到userName
部分,也得到userType
部分。
现在,您可以基于userType
来决定应该从哪个表对用户进行身份验证。
String userNamePart = null;
if (userName.contains(":")) {
int colonIndex = userName.lastIndexOf(":");
userNamePart = userName.substring(0, colonIndex);
}
userNamePart = userNamePart == null ? userName : userNamePart;
String userTypePart = null;
if (userName.contains(":")) {
int colonIndex = userName.lastIndexOf(":");
userTypePart = userName.substring(colonIndex + 1, userName.length());
}