java ladp 乱码_shiro使用LDAP认证

public class LdapAuthorizingRealm extendsJndiLdapRealm {private static final Logger logger = LoggerFactory.getLogger(LdapAuthorizingRealm.class);privateString rootDN;publicString getRootDN() {returnrootDN;

}public voidsetRootDN(String rootDN) {this.rootDN =rootDN;

}/*** 登录时调用

*

*@paramtoken

*@return*@throwsAuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throwsAuthenticationException {

AuthenticationInfo info;try{

info=queryForAuthenticationInfo(token, getContextFactory());

getAuthorizationInfo(((UsernamePasswordToken) token).getUsername());

}catch(AuthenticationNotSupportedException e) {

String msg= "Unsupported configured authentication mechanism";throw newUnsupportedAuthenticationMechanismException(msg, e);

}catch(javax.naming.AuthenticationException e) {

String msg= "LDAP authentication failed.";throw newAuthenticationException(msg, e);

}catch(NamingException e) {

String msg= "LDAP naming error while attempting to authenticate user.";throw newAuthenticationException(msg, e);

}catch(UnknownAccountException e) {

String msg= "账号不存在!";throw newUnknownAccountException(msg, e);

}catch(IncorrectCredentialsException e) {

String msg= "IncorrectCredentialsException";throw newIncorrectCredentialsException(msg, e);

}returninfo;

}/*** 授权

*

*@paramprincipalCollection

*@return

*/@OverrideprotectedAuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {//因为非正常退出,即没有显式调用 SecurityUtils.getSubject().logout()//(可能是关闭浏览器,或超时),但此时缓存依旧存在(principals),所以会自己跑到授权方法里。

if (!SecurityUtils.getSubject().isAuthenticated()) {

doClearCache(principalCollection);

SecurityUtils.getSubject().logout();return null;

}//获取当前登录的用户名

String username =(String) principalCollection.getPrimaryPrincipal();

SimpleAuthorizationInfo authorizationInfo= newSimpleAuthorizationInfo();

Session session=SecurityUtils.getSubject().getSession();

authorizationInfo.setStringPermissions((Set) session.getAttribute("permissions"));returnauthorizationInfo;

}/*** 连接LDAP查询用户信息是否存在

*

* 1. 从页面得到登陆名和密码。注意这里的登陆名和密码一开始并没有被用到。

* 2. 先匿名绑定到LDAP服务器,如果LDAP服务器没有启用匿名绑定,一般会提供一个默认的用户,用这个用户进行绑定即可。

* 3. 之前输入的登陆名在这里就有用了,当上一步绑定成功以后,需要执行一个搜索,而filter就是用登陆名来构造,形如: "CN=*(xn607659)" 。

* 搜索执行完毕后,需要对结果进行判断,如果只返回一个entry,这个就是包含了该用户信息的entry,可以得到该 entry的DN,后面使用。

* 如果返回不止一个或者没有返回,说明用户名输入有误,应该退出验证并返回错误信息。

* 4. 如果能进行到这一步,说明用相应的用户,而上一步执行时得到了用户信息所在的entry的DN,这里就需要用这个DN和第一步中得到的password重新绑定LDAP服务器。

* 5. 执行完上一步,验证的主要过程就结束了,如果能成功绑定,那么就说明验证成功,如果不行,则应该返回密码错误的信息。

* 这5大步就是基于LDAP的一个 “两次绑定” 验证方法

*

*@paramtoken

*@paramldapContextFactory

*@return*@throwsNamingException*/@OverrideprotectedAuthenticationInfo queryForAuthenticationInfo(

AuthenticationToken token, LdapContextFactory ldapContextFactory)throwsNamingException {

Object principal= token.getPrincipal();//输入的用户名

Object credentials = token.getCredentials();//输入的密码

String userName =principal.toString();

String password= new String((char[]) credentials);

LdapContext systemCtx= null;

LdapContext ctx= null;try{//使用系统配置的用户连接LDAP

systemCtx =ldapContextFactory.getSystemLdapContext();

SearchControls constraints= newSearchControls();

constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);//搜索范围是包括子树//String returnedAtts[] = { "uid","displayName","cn","company","department","mailNickname"};//constraints.setReturningAttributes(returnedAtts);

NamingEnumeration results = systemCtx.search(rootDN, "UID=" +principal , constraints);if (results != null && !results.hasMore()) {throw newUnknownAccountException();

}else{while(results.hasMore()) {

SearchResult si=(SearchResult) results.next();

principal= si.getName() + "," +rootDN;

logger.debug(si.getAttributes().get("company").toString());

logger.debug(si.getAttributes().get("department").toString());

}

logger.info("DN=[" + principal + "]");try{//根据查询到的用户与输入的密码连接LDAP,用户密码正确才能连接

ctx =ldapContextFactory.getLdapContext(principal, credentials);

dealUser(userName, password);

}catch(NamingException e) {throw newIncorrectCredentialsException();

}return new SimpleAuthenticationInfo(userName, MD5Util.MD5(userName +password).toLowerCase(), getName());

}

}finally{//关闭连接

LdapUtils.closeContext(systemCtx);

LdapUtils.closeContext(ctx);

}

}/*** 将LDAP查询到的用户保存到sys_user表

*

*@paramuserName*/

private voiddealUser(String userName, String password) {if(StringUtil.isEmpty(userName)) {return;

}//TO DO...

}/*** 获取权限码

*

*@paramusername

*@return

*/

private Map>getAuthorizationInfo(String username) {

Map> authorizationMap = new HashMap>();

Set codeSet = new HashSet();

Session session=SecurityUtils.getSubject().getSession();

//查询数据库的用户权限

//......authorizationMap.put("permissions", codeSet);

session.setAttribute("permissions", codeSet);

logger.debug("当前登录账户:{}的权限集合:{}", username, codeSet);returnauthorizationMap;

}/*** 设定Password校验的Hash算法与迭代次数.这里使用了自定义的加密算法*/@PostConstructpublic voidinitCredentialsMatcher() {

HashedCredentialsMatcher matcher= new HashedCredentialsMatcher("MD5") {

@Overridepublic booleandoCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {

Object credentials=token.getCredentials();

UsernamePasswordToken token1=(UsernamePasswordToken) token;if (credentials == null) {

String msg= "Argument for byte conversion cannot be null.";throw newIllegalArgumentException(msg);

}byte[] bytes = null;if (credentials instanceof char[]) {

bytes= CodecSupport.toBytes(new String((char[]) credentials), PREFERRED_ENCODING);

}else{

bytes=objectToBytes(credentials);

}

String tokenHashedCredentials= MD5Util.MD5(token1.getUsername() + newString(bytes)).toLowerCase();

String accountCredentials=getCredentials(info).toString();returntokenHashedCredentials.equals(accountCredentials);

}

};

matcher.setHashIterations(1);

setCredentialsMatcher(matcher);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值