shiro实现不同用户多realm登录
发表于:2025-02-04 作者:千家信息网编辑
千家信息网最后更新 2025年02月04日,现有app上因功能扩展,需另外一部分用户登录,和原来的用户不在同一张表中。原来的shiro配置和单个realm不能满足多个表中用户(当然也可以在同一个realm中在两个表中查找,一个表查不到就去另一个
千家信息网最后更新 2025年02月04日shiro实现不同用户多realm登录
现有app上因功能扩展,需另外一部分用户登录,和原来的用户不在同一张表中。原来的shiro配置和单个realm不能满足多个表中用户(当然也可以在同一个realm中在两个表中查找,一个表查不到就去另一个表查,这种方式太笨了),所以自己尝试了以下扩展。实现不同的realm获取不同表中的用户。
一、先介绍一个用户时是怎么配置的
1、shiro.xml
2、
package com.su;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.DisabledAccountException;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.util.ByteSource;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import net.zkbc.jcaptcha.util.JCaptchaUtils;import net.zkbc.shiro.authc.IncorrectCaptchaException;import net.zkbc.shiro.authc.UsernameCaptchaToken;import net.zkbc.shiro.authc.UsernamePasswordCaptchaToken;import net.zkbc.shiro.entity.ShiroUser;import net.zkbc.shiro.service.ShiroCaptchaService;import net.zkbc.shiro.service.ShiroUserService;import redis.clients.jedis.Jedis;public class ShiroCaptchaDbRealm extends ShiroDbRealm { @Autowired(required = false) private ShiroCaptchaService captchaService; @Autowired @Qualifier private ShiroUserService shiroUserService; @SuppressWarnings("resource") @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { String loginName = ((UsernamePasswordToken) authcToken).getUsername(); if (authcToken instanceof UsernameCaptchaToken) { Jedis jedis = new Jedis(); String captcha = jedis.get(loginName); //TODO 获取验证码相关 byte[] salt_byte = null; return new SimpleAuthenticationInfo(loginName, captcha, ByteSource.Util.bytes(salt_byte), getName()); } ShiroUser loginUser = shiroUserService.findUserByLoginName(loginName); if (loginUser == null) { throw new UnknownAccountException(); } if (loginUser.isDisabled()) { throw new DisabledAccountException(); } ByteSource salt = ByteSource.Util.bytes(shiroUserService.getSaltBytes(loginUser)); return new SimpleAuthenticationInfo(loginName, loginUser.getPassword(), salt, getName()); }}
3、用postman访问:http://localhost:10001/app/weicheLogin 参数 : {"custNum":"413185410"}
@RequestMapping(value = Urls.WCLOGIN, method = RequestMethod.POST) @ResponseBody public WcCustomerIsExistResponse wcLogin(@Valid @RequestBody WcCustomerIsExistRequest request, BindingResult result, Locale locale) { WcCustomerIsExistResponse response = new WcCustomerIsExistResponse(); if (result.hasErrors()) { Validators.addParameterErrors(response, result, messageSource, locale); return response; } try { mobileService.bindSubject(request.getSessionId()); response = messageMMSService.wcCustomerIsExist(request, response); mobileService.serviceForNoAuthcForm(request.getCustNum(), request, response); } catch (RemoteConnectFailureException e) { LOG.error(e.getMessage(), e); response = mockMessageMMSService.wcCustomerIsExist(request, response); } catch (ParameterException e) { Validators.addParameterErrors(response, e.getMessage(), messageSource, locale); } catch (Exception e) { LOG.error(e.getMessage(), e); response.error(); } return response; }
4、
@Override publicRESPONSE serviceForNoAuthcForm( String loginName, REQUEST request, RESPONSE response) { try { String sessionId = loginNoPassword(loginName).toString(); request.setSessionId(sessionId); response.setSessionId(sessionId); } catch (UnknownAccountException e) { LOG.debug(e.getMessage(), e); response.error(MessageError.ERROR_AUTH); } catch (DisabledAccountException e) { LOG.debug(e.getMessage(), e); response.error(MessageError.ERROR_DISABLED); } catch (IncorrectCredentialsException e) { LOG.debug(e.getMessage(), e); response.error(MessageError.ERROR_AUTH); } catch (ExcessiveAttemptsException e) { LOG.debug(e.getMessage(), e); response.error(MessageError.ERROR_ATTEMPTS); } catch (Exception e) { LOG.error(e.getMessage(), e); response.error(); } return response; } private Serializable loginNoPassword(String loginName) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getRequest(); UsernameNoPasswordCaptchaToken token=new UsernameNoPasswordCaptchaToken(loginName,null,null); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); } catch (InvalidSessionException e) { subject.logout(); //subject.login(token); } Session session = subject.getSession(); Serializable sessionId = session.getId(); LOG.debug("Session with id [{}] startTimestamp:{}", sessionId, session.getStartTimestamp().getTime()); try { Thread.sleep(100); } catch (Exception ignored) { } session.touch(); LOG.debug("Session with id [{}] lastAccessTime:{}", sessionId, session.getLastAccessTime().getTime()); processConcurrentSessions(); return sessionId; }
5、
import org.apache.shiro.authc.UsernamePasswordToken;public class UsernameNoPasswordCaptchaToken extends UsernamePasswordToken { private static final long serialVersionUID = 1L; private String username; public UsernameNoPasswordCaptchaToken(String username,String password,String host) { super(username,password,host); this.username = username; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }
二、多个realm
1、
2、
import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.DisabledAccountException;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.util.ByteSource;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;public class QggRealm extends AuthorizingRealm{ @Autowired @Qualifier("qggUserService") private ShiroUserService shiroUserService; @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { // TODO Auto-generated method stub return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken) throws AuthenticationException { String loginName = ((CustomizedToken) authcToken).getUsername(); ShiroUser loginUser = shiroUserService.findUserByLoginName(loginName); if (loginUser == null) { throw new UnknownAccountException(); } if (loginUser.isDisabled()) { throw new DisabledAccountException(); } ByteSource salt = ByteSource.Util.bytes(shiroUserService.getSaltBytes(loginUser)); return new SimpleAuthenticationInfo(loginName, loginUser.getPassword(), salt, getName()); } }
2、
public class WeicheRealm extends AuthorizingRealm{ @Autowired @Qualifier("weicheUserService") private ShiroUserService shiroUserService; @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { // TODO Auto-generated method stub return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken) throws AuthenticationException { String loginName = ((CustomizedToken) authcToken).getUsername(); ShiroUser loginUser = shiroUserService.findUserByLoginName(loginName); if (loginUser == null) { throw new UnknownAccountException(); } if (loginUser.isDisabled()) { throw new DisabledAccountException(); } ByteSource salt = ByteSource.Util.bytes(shiroUserService.getSaltBytes(loginUser)); return new SimpleAuthenticationInfo(loginName, loginUser.getPassword(), salt, getName()); } }
3、入参WcCustomerIsExistRequest 类中包括登录名 custNum和登录类型loginType (Qgg和Weiche)
用postman访问:http://localhost:10001/app/mutilRealmLogin 参数 : {"custNum":"413185410","loginType":"Weiche"}
//@RequestMapping(value = Urls.MUTILREALMLOGIN, method = RequestMethod.POST) @ResponseBody public WcCustomerIsExistResponse mutiRealmLogin(@Valid @RequestBody WcCustomerIsExistRequest request, BindingResult result, Locale locale) { WcCustomerIsExistResponse response = new WcCustomerIsExistResponse(); if (result.hasErrors()) { Validators.addParameterErrors(response, result, messageSource, locale); return response; } try { mobileService.bindSubject(request.getSessionId()); mobileService.serviceForMultiRealmAuthcForm(request.getCustNum(),request.getLoginType(), request, response); } catch (RemoteConnectFailureException e) { response = mockMessageMMSService.wcCustomerIsExist(request, response); } catch (ParameterException e) { Validators.addParameterErrors(response, e.getMessage(), messageSource, locale); } catch (Exception e) { response.error(); } return response; }
4、
@Override publicRESPONSE serviceForMultiRealmAuthcForm( String loginName, String loginType, REQUEST request, RESPONSE response) { try { String sessionId = loginMultiRealm(loginName,loginType).toString(); request.setSessionId(sessionId); response.setSessionId(sessionId); } catch (UnknownAccountException e) { LOG.debug(e.getMessage(), e); response.error(MessageError.ERROR_AUTH); } catch (DisabledAccountException e) { LOG.debug(e.getMessage(), e); response.error(MessageError.ERROR_DISABLED); } catch (IncorrectCredentialsException e) { LOG.debug(e.getMessage(), e); response.error(MessageError.ERROR_AUTH); } catch (ExcessiveAttemptsException e) { LOG.debug(e.getMessage(), e); response.error(MessageError.ERROR_ATTEMPTS); } catch (Exception e) { LOG.error(e.getMessage(), e); response.error(); } return response; }
5、
private Serializable loginMultiRealm(String loginName,String loginType) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getRequest(); CustomizedToken token=new CustomizedToken(loginName,null,loginType); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); } catch (InvalidSessionException e) { subject.logout(); //subject.login(token); } Session session = subject.getSession(); Serializable sessionId = session.getId(); LOG.debug("Session with id [{}] startTimestamp:{}", sessionId, session.getStartTimestamp().getTime()); try { Thread.sleep(100); } catch (Exception ignored) { } session.touch(); LOG.debug("Session with id [{}] lastAccessTime:{}", sessionId, session.getLastAccessTime().getTime()); processConcurrentSessions(); return sessionId; }
6、
import org.apache.shiro.authc.UsernamePasswordToken;public class CustomizedToken extends UsernamePasswordToken { //登录类型,判断是哪种用户登录 private String loginType; public CustomizedToken(final String username, final String password,String loginType) { super(username,password); this.loginType = loginType; } public String getLoginType() { return loginType; } public void setLoginType(String loginType) { this.loginType = loginType; }}
7、重要:这个类选择使用哪个realm
import java.util.ArrayList;import java.util.Collection;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.pam.ModularRealmAuthenticator;import org.apache.shiro.realm.Realm;/** * @author Alan_Xiang * 自定义Authenticator * 注意,当需要分别定义处理普通用户和管理员验证的Realm时,对应Realm的全类名应该包含字符串"User",或者"Admin"。 * 并且,他们不能相互包含,例如,处理普通用户验证的Realm的全类名中不应该包含字符串"Admin"。 */public class CustomizedModularRealmAuthenticator extends ModularRealmAuthenticator { @Override protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { // 判断getRealms()是否返回为空 assertRealmsConfigured(); // 强制转换回自定义的CustomizedToken CustomizedToken customizedToken = (CustomizedToken) authenticationToken; // 登录类型 String loginType = customizedToken.getLoginType(); // 所有Realm Collectionrealms = getRealms(); // 登录类型对应的所有Realm Collection typeRealms = new ArrayList<>(); for (Realm realm : realms) { if (realm.getName().contains(loginType)) typeRealms.add(realm); } // 判断是单Realm还是多Realm if (typeRealms.size() == 1) return doSingleRealmAuthentication(typeRealms.iterator().next(), customizedToken); else return doMultiRealmAuthentication(typeRealms, customizedToken); }}
参考:https://blog.csdn.net/xiangwanpeng/article/details/54802509
用户
登录
类型
验证
不同
普通
参数
多个
字符
字符串
类名
处理
配置
重要
两个
功能
单个
方式
管理员
还是
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
广西佳宇网络技术有限公司刘琨
手机网络安全恐怖事件
上海纵游网络技术
数据库行是属性吗
下发网络安全审查办法
论坛软件开发教程
网络安全 cscd
封开县网络安全宣传
网络安全观的教案
智能网络技术直销价格
完全免费的软件开发平台
ngb网络技术与应用实验
杨浦区网络技术服务零售价格
兰州软件开发
长风软件开发研究所张敏
bma服务器管理
数据库大批量数据处理
岛风go代理服务器地址
带宽管理服务器
汽车软件开发上市公司有哪些
央视报道新华互联网科技
我的世界灵剑传服务器
车坏在服务器怎么办
分布式文件系统是什么数据库
福建连江网络软件开发
网络新闻编辑网络安全
各公司网络安全活动形式多样
软件开发工程合作 湖南岚鸿
猪兼强网络技术
网络安全班课讲稿