spring security 多级认证/远程认证/多provider
需求场景实现其他系统的用户能够登录到系统B之前系统A与系统B并无关联,简单说就是分别有一套用户体系,各自有各自的登录功能。现在需要让系统A的用户使用账号密码也能登录到系统B。实现要点:如何区分当前的登录用户是系统A的还是系统B的?因为不同的用户需要到对应的系统做验证。可以通过用户名的特殊标识、配置(不太现实)、加载本地所有账号、前端传用户类型等等方式来判断当前的登录用户是系统A...
需求场景
实现其他系统的用户能够登录到系统B
之前系统A与系统B并无关联,简单说就是分别有一套用户体系,各自有各自的登录功能。
现在需要让系统A的用户使用账号密码也能登录到系统B。
实现
要点:
- 如何区分当前的登录用户是系统A的还是系统B的?因为不同的用户需要到对应的系统做验证。
可以通过用户名的特殊标识、配置(不太现实)、加载本地所有账号、前端传用户类型等等方式来判断当前的登录用户是系统A还是系统B。之后走不同的认证流程。
- 系统A用户登录到系统B之后,权限如何管理?
在系统B中创建一个用户来关联系统A的用户,利用系统B中的用户来管理权限。(同步用户)
项目使用的是spring security,通过扩展spring security 认证机制来实现此功能。(多 provider)
代码:
创建一个远程认证的Provider
// 远程认证 Provider
public class RemoteAuthenticationProvider implements AuthenticationProvider {
private UserDetailsService userDetailsService;
private RemoteService remoteService;// 远程认证服务
public RemoteAuthenticationProvider(){
this.userDetailsService = SpringContextUtil.getBean(UserDetailsService.class);
this.remoteService= SpringContextUtil.getBean(RemoteService .class);
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
// 本地管理员,不做远程认证
if("admin".equals(username)){
// 此处涉及spring security的认证机制,当前Provider返回null时,则会查找下一个Provider进行认证
return null;
}
try {
// 1、远程验证帐号密码
Object resp = remoteService.verifyPwd(username, password);
if(!resp.isSuccess()){
throw new RuntimeException(resp.getMsg());
}
// 2、同步用户,便于管理权限
remoteService.syncUserIfNotExist(username);
} catch (Exception e) {
log.error("远程验证失败", e);
throw new InternalAuthenticationServiceException("远程验证失败", e);
}
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
return result;
}
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}
配置多 Provider,先走远程认证的Provider,再走本地数据库认证的Provider
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
RemoteAuthenticationProvider remoteAuthenticationProvider = new RemoteAuthenticationProvider();
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
// ProviderManager providerManager = new ProviderManager(Collections.singletonList(daoAuthenticationProvider));
// auth.parentAuthenticationManager(providerManager);
auth.authenticationProvider(remoteAuthenticationProvider);// 远程认证在前
auth.authenticationProvider(daoAuthenticationProvider);// 本地认证在后
// super.configure(auth);
}
}
关于 RemoteAuthenticationProvider 中 return null;的说明:
spring security的认证机制是当前Provider返回null时,则会查找下一个Provider进行认证。所以也能解释在SecurityConfiguration 中把RemoteAuthenticationProvider 放在 DaoAuthenticationProvider 之前,当用户不需要远程认证时,只需要在RemoteAuthenticationProvider 返回null,则会进入DaoAuthenticationProvider进行本地认证。
end
更多推荐




所有评论(0)