共计 2875 个字符,预计需要花费 8 分钟才能阅读完成。
通常在根据 LDAP 进行身份验证时一般进行以下三步:
- 利用一个 LDAP 用户的用户名和密码绑定到 LDAP 服务器。
- 在 LDAP 中检索一个用户的条目,然后将提供的密码和检索到的 LDAP 记录中进行验证。
- 根据 LDAP 提供的记录,再去本系统中查找授权信息。
Shiro 提供了 DefaultLdapRealm
,只做了第二步,根据用户的条目和密码来验证。并不能满足我们的需求,所以肯定是要定制化 LdapRealm。
这里使用 Spring Ldap 来简化 Ldap 操作
public class LdapRealm extends AuthorizingRealm {private static final Logger logger = LoggerFactory.getLogger(LdapRealm.class);
private LdapTemplate ldapTemplate;
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private MenuService menuService;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String username = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
try {LdapQuery ldapQuery = LdapQueryBuilder.query().base("DC=example,DC=com").searchScope(SearchScope.SUBTREE)
.filter("(sAMAccountName={0})", username);
boolean authResult = ldapTemplate.authenticate(ldapQuery.base(), ldapQuery.filter().encode(), password);
if (!authResult) {logger.debug("ldap authentication for {} failed", username);
return null;
}
User ldapUser = (User) ldapTemplate.searchForObject(ldapQuery, new LdapUserAttrMapper());
User user = userService.selectUserById(ldapUser.getUserId());
if (user == null) {
// 用户名不存在抛出异常
throw new UnknownAccountException();}
if (user.getRemoveFlag()) {
// 用户被管理员锁定抛出异常
throw new LockedAccountException();}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, token.getCredentials(),
"LdapRealm");
return authenticationInfo;
} catch (Exception e) {logger.error("ldap authentication failed", e.toString());
return null;
}
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {Long userId = ShiroUtils.getUserId();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 角色加入 AuthorizationInfo 认证对象
info.setRoles(roleService.selectRoleKeys(userId));
// 权限加入 AuthorizationInfo 认证对象
info.setStringPermissions(menuService.selectPermsByUserId(userId));
return info;
}
public LdapTemplate getLdapTemplate() {return ldapTemplate;}
public void setLdapTemplate(LdapTemplate ldapTemplate) {this.ldapTemplate = ldapTemplate;}
}
关键的代码如下,验证用户和获取 LDAP 用户信息
LdapQuery ldapQuery = LdapQueryBuilder.query().base("DC=example,DC=com").searchScope(SearchScope.SUBTREE)
.filter("(sAMAccountName={0})", username);
boolean authResult = ldapTemplate.authenticate(ldapQuery.base(), ldapQuery.filter().encode(), password);
User ldapUser = (User) ldapTemplate.searchForObject(ldapQuery, new LdapUserAttrMapper());
Spring 的 ldap 配置如下:
<bean id="ldapContextSource" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://192.168.100.1:3268"/>
<property name="userDn" value="CN=Reader"/>
<property name="password" value="secret"/>
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<property name="contextSource" ref="ldapContextSource"/>
</bean>
<bean id="ldapRealm" class="com.example.shiro.LdapRealm">
<property name="ldapTemplate" ref="ldapTemplate"/>
</bean>
正文完