经过近一周的努力,终于解决了这个问题。
通过 eclipse 调试时,我发现 SAMLAuthenticationProvider 内部有一个方法的根本原因getEntitlements
这引起了问题。
protected Collection<? extends GrantedAuthority> getEntitlements(SAMLCredential credential, Object userDetail) {
if (userDetail instanceof UserDetails) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.addAll(((UserDetails) userDetail).getAuthorities());
return authorities;
} else {
return Collections.emptyList();
}
}
这里检查 userDetail 对象是否是 UserDetails 类的实例,然后返回所有权限列表,否则将返回空权限列表。
基于表单的身份验证可以返回UserDetails
对象,但如果用户通过 IDP 发起 SSO 登录,则类型为对象UsernamePasswordAuthenticationToken
将会返回。因此,它正在获取带有用户详细信息对象的 grantAuthority 的空列表。
所以我延伸SAMLAuthenticationProvider
在我的应用程序中并覆盖以下方法
@Override
public Collection<? extends GrantedAuthority> getEntitlements(SAMLCredential credential, Object userDetail)
{
logger.info("****** object is instance of UserDetails :"+ (userDetail instanceof UserDetails));
if (userDetail instanceof UserDetails)
{
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.addAll(((UserDetails) userDetail).getAuthorities());
return authorities;
}
else if(userDetail instanceof UsernamePasswordAuthenticationToken)
{
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.addAll(((UsernamePasswordAuthenticationToken) userDetail).getAuthorities());
return authorities;
} else {
return Collections.emptyList();
}
}
然后,我将自定义的authenticationProvider引用与自定义的SAMLUserDetailsService类引用一起放入saml-security.xml文件中。
<bean id="samlAuthenticationProvider" class="com.mercatus.security.MercatusSAMLAuthenticationProvider">
<property name="userDetails" ref="samlUserDetailsService" />
</bean>
<bean id="samlUserDetailsService" class="com.mercatus.security.MercatusSAMLUserDetailsService"/>
上面的配置救了我。登录后我可以访问受保护的资源。
我花了整整一周的时间在 FilterChainProxy 和许多其他过滤器中进行调试,因为拦截器 URL 被重定向到 FilterChainProxy。
我发布详细信息是因为它可能对面临类似问题的其他人有所帮助。