shiro实现不同用户多realm登录
发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,现有app上因功能扩展,需另外一部分用户登录,和原来的用户不在同一张表中。原来的shiro配置和单个realm不能满足多个表中用户(当然也可以在同一个realm中在两个表中查找,一个表查不到就去另一个
千家信息网最后更新 2026年11月03日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 Collection realms = 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安全错误
数据库的锁怎样保障安全
南京欣网互联网络科技
互联网科技公司排名
互联网科技公司经营范围
科技互联网企业
国智互联网科技
互联网品科技
广州互联网科技公司
互联网金融 金融科技
互联网与新科技
互联网高科技企业
国外互联网科技网站
西藏七维空间互联网科技有限公司
科技互联网的估值
剑昆互联网络科技有限公司临桂
港股科技和互联网
互联网科技创新的路径
徐州市互联网科技有限公司
云南省自由互联网科技有限公司
美国互联网科技公司
利用互联网等科技手段
瑰夏咖啡
什么是科技互联网
小米移动互联网科技园
互联网 的科技创新
互联网科技网站
阿里巴巴算科技企业还是互联网
深圳市优智互联网科技有限公司
链环科技传统企业怎么转型互联网
如何创新互联网科技
上海互联网科技公司ppt