千家信息网

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        public  RESPONSE 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        public  RESPONSE 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

0