我很高兴你在这里阅读我的问题:)
我正在为一家销售商店开发一款春季版的网络应用程序。我制作了一个使用formLogin()进行用户身份验证的登录系统(它的工作原理很有魅力),但当涉及到检测用户登录在哪台计算机时,我遇到了一个问题。另一个事实是,只有特定的计算机才能访问该网站,并且一次只能访问一个用户。此外,我在与Spring数据JPA链接的数据库中实现了(用户和终端),并且终端对用户有一个外键(当没有人连接时为null)。
经过3天的谷歌搜索,我得出结论,实现这一点的最佳方法是在每台计算机中安装X.509证书,以进行相互身份验证,并使用loginForm获得用户权限。(终端没有权限,但配置类似"这应该与收银机一起使用"或"这应该使用收据打印机")。
所以,代码部分。。。这是我实际的Spring Security配置:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailsService;
@Autowired
DataSource dataSource;
@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/index", "/static/**", "/login", "/catalogo/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.invalidateHttpSession(true)
.clearAuthentication(true)
.and()
.rememberMe()
.rememberMeParameter("remember-me")
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(86400).and()
.csrf()
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Bean
public AuthenticationTrustResolver getAuthenticationTrustResolver() {
return new AuthenticationTrustResolverImpl();
}
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl tokenRepositoryImpl = new JdbcTokenRepositoryImpl();
tokenRepositoryImpl.setDataSource(dataSource);
return tokenRepositoryImpl;
}
}
这是我的UserDetailService:
@Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
private static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);
// This is my user model service in Spring-data JPA, I have one too for terminals
@Autowired
private SecurityUserService securityUserService;
@Transactional(readOnly=true)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
SecurityUser user = securityUserService.findByUsername(username);
logger.info("User : {}", user);
if(user==null){
logger.info("User not found");
throw new UsernameNotFoundException("Username not found");
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(), user.getPassword(), true, true, true,
true, getGrantedAuthorities(getPermissions(user)));
}
private List<GrantedAuthority> getGrantedAuthorities(List<String> permisos) {
List<GrantedAuthority> authorities = new ArrayList<>();
for (String permiso : permisos) {
authorities.add(new SimpleGrantedAuthority(permiso));
}
return authorities;
}
private List<String> getPermissions(SecurityUser user) {
List<String> privileges = new ArrayList<>();
List<SecurityPermission> collection = new ArrayList<>();
for (SecurityRole role : user.getRoles()) {
collection.addAll(role.getPermissions());
}
collection.addAll(user.getPermissions());
for (SecurityPermission item : collection) {
privileges.add(item.getName());
}
return privileges;
}
}
基本上,现在我必须添加X.509证书身份验证。我在没有登录表单的情况下完成了它,效果很好,但我不知道如何将两者结合起来。
谢谢你的帮助。
PS:如果你认为你有另一个可能的解决方案,不要害怕发布
如果您不打算使用客户端证书身份验证来获取连接用户的详细信息,那么您只需要建立一个具有双向身份验证的安全TLS通道。您不需要修改您的春季应用程序
配置要求客户端提供证书的TLS通道。浏览器将提示用户从密钥库中选择一个。服务器将对其进行验证,如果可以接受,将建立安全通道。
配置对于每台服务器都是特定的,所以请查看您的文档。
您需要在每台计算机中安装客户端证书,如果您使用的是自签名证书,请在信任存储中安装公共部分,以避免浏览器警告
可以在客户端使用X509Certificate来识别用户并避免登录表单。它需要为每个用户颁发证书,并将其安装在用户要使用的计算机中。如果计算机是共享的,那么证书应该用密码保护。可能不是一个好的选择你