资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

shiro实现不同用户多realm登录

现有app上因功能扩展,需另外一部分用户登录,和原来的用户不在同一张表中。原来的shiro配置和单个realm不能满足多个表中用户(当然也可以在同一个realm中在两个表中查找,一个表查不到就去另一个表查,这种方式太笨了),所以自己尝试了以下扩展。实现不同的realm获取不同表中的用户。

创新互联公司主要从事网页设计、PC网站建设(电脑版网站建设)、wap网站建设(手机版网站建设)、响应式网站开发、程序开发、网站优化、微网站、小程序制作等,凭借多年来在互联网的打拼,我们在互联网网站建设行业积累了丰富的成都网站建设、做网站、网站设计、网络营销经验,集策划、开发、设计、营销、管理等多方位专业化运作于一体。

一、先介绍一个用户时是怎么配置的

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


当前题目:shiro实现不同用户多realm登录
当前路径:http://cdkjz.cn/article/joegoi.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220