天天看点

Apache Shiro 身份验证

1、什么是Apache Shiro

Apache Shiro,Java的一个开源安全框架,类似的还有Spring Security,用于简洁地处理身份验证,授权,企业多个系统会话管理,加密服务等。

2、三大主要组件

Subject:代表了当前用户,与应用代码直接交互的shiro对外API;

SecurityManager:安全管理器,所有与安全有关的操作都会与SecurityManager交互,管理这所有的Subject,负责与其他shiro组件进行交互,是shiro的核心组件

Realm:域,Shiro从realm中获取安全数据(用户/角色/权限),即安全数据源,由开发人员自己注入。

3、其他组件

在shiro的用户权限认证过程中其通过两个方法来实现:

1、Authentication:是验证用户身份的过程。

2、Authorization:是授权访问控制,用于对用户进行的操作进行人证授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。

3、SessionManager :Shiro为任何应用提供了一个会话编程范式。 4、CacheManager :对Shiro的其他组件提供缓存支持。

4、Shiro标签

<shiro:guest> 验证未登录用户

<shiro:user>验证已登陆用户

<shiro:authenticated>已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。

<shiro:notAuthenticated>未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户。

 <shiro:principal/>输出当前用户信息,通常为登录帐号信息。Hello, <shiro:principal/>, how are you today?

<shiro:hasRole name="administrator"> 验证当前用户是否属于该角色。

<shiro:lacksRole name="administrator"> 与hasRole标签逻辑相反,当用户不属于该角色时验证通过。 

<shiro:hasAnyRoles name="developer, project manager, administrator">验证当前用户是否属于以下任意一个角色

<shiro:hasPermission name="user:create">验证当前用户是否拥有指定权限。

<shiro:hasPermission name="user:create"> 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。

注意:会进入授权方法一共有三种情况!

1、subject.hasRole(“admin”) 或 subject.isPermitted(“admin”):自己去调用这个是否有什么角色或者是否有什么权限的时候;

2、@RequiresRoles("admin") :在方法上加注解的时候;

3、[@shiro.hasPermission name = "admin"][/@shiro.hasPermission]:在页面上加shiro标签的时候,即进这个页面的时候扫描到有这个标签的时候。

5.配置(这里主要展示如何配置多个realm,支持用户名密码登陆和手机验证码登陆)

pom.xml

<!-- shiro start -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-aspectj</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
        </dependency>
        <!-- shiro end -->
           

web.xml

<filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
           

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd" default-lazy-init="true">

    <!-- shiro集群改造,参考:http://git.oschina.net/zhmlvft/spring_shiro_redis http://git.oschina.net/1231/spinach -->

	<bean id="modelAuthricator" class="com.jusfoun.socialgrid.shiro.DefaultModularRealm">
	 	<property name="definedRealms">    
            <map>    
                <entry key="shiroDbRealm" value-ref="shiroDbRealm" />    
                <entry key="shiroVertifyRealm" value-ref="shiroVertifyRealm" />    
            </map>    
        </property>
    </bean>
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realms">
           <list>
             	<ref bean="shiroDbRealm" />  
	            <ref bean="shiroVertifyRealm" /> 
           </list>
        </property>
        <property name="authenticator" ref="modelAuthricator"/>
        <property name="sessionManager" ref="sessionManager" />
        <property name="cacheManager" ref="redisCacheManager" />
    </bean>
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <property name="sessionDAO" ref="sessionDAO" />
        <property name="sessionIdCookieEnabled" value="true" />
        <property name="sessionIdCookie" ref="sessionIdCookie" />
        <property name="deleteInvalidSessions" value="true" />
        <property name="sessionValidationSchedulerEnabled" value="true" />
    </bean>
    <bean id="redisCacheManager" class="com.itmuch.core.shiro.RedisCacheManager">
        <property name="redisManager" ref="redisManager" />
    </bean>
    <bean id="redisManager" class="com.itmuch.core.shiro.RedisManager">
        <property name="expire" value="${redis.expireTime}" />
        <property name="host" value="${redis.host}" />
        <property name="password" value="${redis.pass}" />
        <property name="port" value="${redis.port}" />
        <property name="timeout" value="${redis.maxWait}" />
    </bean>
    
    <!-- session 保存到cookie,关闭浏览器下次可以直接登录认证,当maxAge为-1不会写cookie。 -->
    <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="sid" />
        <property name="httpOnly" value="true" />
        <!-- 浏览器关闭session失效,不计入cookie -->
        <property name="maxAge" value="-1" />
    </bean>

    <bean id="shiroDbRealm" class="com.jusfoun.socialgrid.shiro.ShiroDbRealm">
        <property name="credentialsMatcher" ref="credentialsMatcher"></property>
    </bean>

	<bean id="shiroVertifyRealm" class="com.jusfoun.socialgrid.shiro.ShiroVertifyRealm">
    </bean>
    <!-- 自定义身份验证器,用于限制用户尝试次数,防止暴力登陆 -->
    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="md5"></property>
        <!-- true means hex encoded, false means base64 encoded -->
        <property name="storedCredentialsHexEncoded" value="true" />
        <!-- <property name="hashIterations" value="1" /> -->
    </bean>

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value="/login" />
        <!-- <property name="unauthorizedUrl" value="${adminPath}" /> -->
        <property name="successUrl" value="/" />
        <property name="filters">
            <map>
                <entry key="authc" value-ref="authcFilter" />
            </map>
        </property>
        <property name="filterChainDefinitions">
            <value>
            	/*.json = anon
                /common/upload = anon
                /static/** = anon
                /druid/* = perms[sys:datasource:view]
                /vertificate/sendDxCode = anon
                /sendDxCode = anon
                /login = anon
                /logout = logout
                /getVerifyCode = anon
                /loginByVertifyCode = anon

                /** = user
            </value>
        </property>
    </bean>
<bean id="authcFilter" class="com.jusfoun.socialgrid.shiro.MyFormAuthenticationFilter"></bean>

    <!-- 自定义shiro的sessionDao,把session写入redis -->
    <bean id="sessionDAO" class="com.itmuch.core.shiro.RedisSessionDao">
        <constructor-arg ref="redisTemplate" />
        <constructor-arg value="${redis.expireTime}" />
    </bean>

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

</beans>
           

自定义异常类CaptchaException

package com.jusfoun.socialgrid.shiro;

import org.apache.shiro.authc.AuthenticationException;

/**
 * 验证码异常类
 * @author user
 *
 */
public class CaptchaException extends AuthenticationException{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public CaptchaException() {
		super();
	}

	public CaptchaException(String message, Throwable cause) {
		super(message, cause);
	}

	public CaptchaException(String message) {
		super(message);
	}

	public CaptchaException(Throwable cause) {
		super(cause);
	}

}
           

DefaultModularRealm类

package com.jusfoun.socialgrid.shiro;

import java.util.Collection;
import java.util.Map;

import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.util.CollectionUtils;

public class DefaultModularRealm extends ModularRealmAuthenticator {  
    private Map<String, Object> definedRealms;  
  
    /** 
     * 多个realm实现 
     */  
    @Override  
    protected AuthenticationInfo doMultiRealmAuthentication(  
            Collection<Realm> realms, AuthenticationToken token) {  
        return super.doMultiRealmAuthentication(realms, token);  
    }  
  
    /** 
     * 调用单个realm执行操作 
     */  
    @Override  
    protected AuthenticationInfo doSingleRealmAuthentication(Realm realm,  
            AuthenticationToken token) {  
  
        // 如果该realms不支持(不能验证)当前token  
        if (!realm.supports(token)) {  
            throw new ShiroException("token错误!");  
        }  
        AuthenticationInfo info = null;  
        try {  
            info = realm.getAuthenticationInfo(token);  
  
            if (info == null) {  
                throw new ShiroException("token不存在!");  
            }  
        } catch (Exception e) {  
            throw new ShiroException("用户名或者密码错误!");  
        }  
        return info;  
    }  
  
    /** 
     * 判断登录类型执行操作 
     */  
    @Override  
    protected AuthenticationInfo doAuthenticate(  
            AuthenticationToken authenticationToken)  
            throws AuthenticationException {  
        this.assertRealmsConfigured();  
  
        Realm realm = null;  
  
        if(authenticationToken instanceof UsernamePasswordToken){
        	realm = (Realm) this.definedRealms.get("shiroDbRealm");
        }
        if(authenticationToken instanceof UsernamePasswordCaptchaToken){
        	realm = (Realm) this.definedRealms.get("shiroVertifyRealm");
        }
        if (realm == null) {  
            return null;  
        }  
  
        return this.doSingleRealmAuthentication(realm, authenticationToken);  
    }  
  
    /** 
     * 判断realm是否为空 
     */  
    @Override  
    protected void assertRealmsConfigured() throws IllegalStateException {  
        this.definedRealms = this.getDefinedRealms();  
        if (CollectionUtils.isEmpty(this.definedRealms)) {  
            throw new ShiroException("值传递错误!");  
        }  
    }  
  
    public Map<String, Object> getDefinedRealms() {  
        return this.definedRealms;  
    }  
  
    public void setDefinedRealms(Map<String, Object> definedRealms) {  
        this.definedRealms = definedRealms;  
    }  
} 
           

MyFormAuthenticationFilter类

package com.jusfoun.socialgrid.shiro;

import java.io.PrintWriter;
import java.util.Date;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itmuch.core.constants.CodeConstant;
import com.itmuch.core.util.ErrorMsgUtil;
import com.itmuch.core.web.converter.Result;
import com.jusfoun.socialgrid.admin.service.UserService;
import com.jusfoun.socialgrid.util.common.IPUtil;

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyFormAuthenticationFilter.class);

    public static final String DEFAULT_CAPTCHA_PARAM = "captcha";
	 
	private String captchaParam = DEFAULT_CAPTCHA_PARAM;
 
	public String getCaptchaParam() {
 
		return captchaParam;
 
	}
 
	protected String getCaptcha(ServletRequest request) {
 
		return WebUtils.getCleanParam(request, getCaptchaParam());
 
	}
    @Resource
    private UserService userService;

    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        String principal = (String) subject.getPrincipal();

        com.jusfoun.socialgrid.admin.domain.User currUser = this.userService.selectByUsername(principal);

        if (currUser != null) {

            // 最后一次登陆ip 与时间等等
            String ip = IPUtil.getIpAddr((HttpServletRequest) request);

            LOGGER.info("用户:{}登陆成功, IP:{}, 当前时间:{}.", currUser.getUsername(), ip, new Date());
        }

        return super.onLoginSuccess(token, subject, request, response);
    }

    /**
     * 适应ajax情况下用户访问不允许访问的页面时的情况
     * 参考: http://my.oschina.net/WMSstudio/blog/162594
     * 参考: http://ketayao.com/view/9
     * 参考: http://blog.csdn.net/shadowsick/article/details/39021265
     */
    @Override
    protected boolean onAccessDenied(ServletRequest req, ServletResponse response) throws Exception {
        HttpServletRequest request = (HttpServletRequest) req;
        String accept = request.getHeader("accept");
        String header = request.getHeader("X-Requested-With");
        // ajax 请求
        if (((accept != null) && (accept.indexOf("application/json") > -1)) || ((header != null) && (header.indexOf("XMLHttpRequest") > -1))) {
            if (!this.isLoginRequest(req, response)) {
                Result result = ErrorMsgUtil.error("用户未登录", "用户未登录, 或用户登录已超时, 请重新登录", CodeConstant.UNKNOW_ERROR_CODE);
                ObjectMapper om = new ObjectMapper();
                om.setSerializationInclusion(Include.NON_NULL);
                String writeValueAsString = om.writeValueAsString(result);

                response.setContentType("text/json; charset=UTF-8");
                response.setCharacterEncoding("UTF-8");
                PrintWriter out = response.getWriter();
                out.println(writeValueAsString);
                out.flush();
                out.close();
                return false;
            } else {
                return true;
            }
        } else {
            return super.onAccessDenied(request, response);
        }
    }

}
           

ShiroDbRealm类,第一个realm用于用户名密码登陆;这里变态的要求三个用户表,用时按照自己的需求修改即可

package com.jusfoun.socialgrid.shiro;

import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.itmuch.core.constants.SessionConstants;
import com.itmuch.core.util.SubjectUtil;
import com.jusfoun.socialgrid.admin.domain.CommissionUser;
import com.jusfoun.socialgrid.admin.domain.CompanyUser;
import com.jusfoun.socialgrid.admin.domain.User;
import com.jusfoun.socialgrid.admin.persistence.CommissionUserMapper;
import com.jusfoun.socialgrid.admin.persistence.CompanyUserMapper;
import com.jusfoun.socialgrid.admin.service.RoleService;
import com.jusfoun.socialgrid.admin.service.UserService;
import com.jusfoun.socialgrid.gridManager.domain.GridManager;
import com.jusfoun.socialgrid.gridManager.persistence.GridManagerMapper;

public class ShiroDbRealm extends AuthorizingRealm {
    @Resource
    private UserService userService;
    @Resource
    private RoleService roleService;
    @Autowired
    public GridManagerMapper gridMp;
    @Autowired
    public CommissionUserMapper commMp;
    @Autowired
    public CompanyUserMapper comUserMp;
    

    private static final Logger LOGGER = LoggerFactory.getLogger(ShiroDbRealm.class);

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();

        // 1. 通过用户id,查询用户具有的角色(查询sys_admin_role)
        Long id = SubjectUtil.getUser().getId();
        // 如果是超级管理员, 则拥有所有权限, 不受角色约束
        List<String> permissions = null;
        if (1L == id) {
            permissions = this.userService.selectAllPermissions();
        }
        // 并非超管
        else {
            List<Long> roleIds = this.userService.selectRoleIdListByUserId(id);
            if ((roleIds != null) && !roleIds.isEmpty()) {
                // 2. 通过角色id, 查询角色具有的权限
                permissions = this.userService.selectPermissionsByRoleIds(roleIds);

            }
        }
        if ((permissions != null) && !permissions.isEmpty()) {
            auth.addStringPermissions(permissions);
            return auth;
        }
        return null;
    }

    /**
     * 认证回调函数,登录时调用.
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String userName = token.getUsername();
        LOGGER.info("用户:{}尝试登陆.", userName);
        String roleId = (String)SecurityUtils.getSubject().getSession().getAttribute("role_id");
        User user = null;
        if("1".equals(roleId)){
        	user = this.userService.selectByUsername(userName);
        }else if("2".equals(roleId)){
        	//委办局人员登录
        	List<CommissionUser> list = commMp.selectCommByName(userName);
        	if(list!=null&&list.size()!=0){
        		CommissionUser commUser = list.get(0);
        		user = new User();
        		user.setUsername(commUser.getUsername());
        		user.setMobile(commUser.getMobile());
        		user.setId(commUser.getId());
        		user.setPassword(commUser.getPassword());
        		user.setSalt(commUser.getSalt());
        	}
        }else if("3".equals(roleId)||"4".equals(roleId)){
        	//网格长和网格员登录
        	List<GridManager> list = gridMp.selectGridMgrByName(userName);
        	if(list!=null&&list.size()!=0){
        		GridManager gridMgr = list.get(0);
        		user = new User();
        		user.setUsername(gridMgr.getUsername());
        		user.setMobile(gridMgr.getMobile());
        		user.setId(gridMgr.getId());
        		user.setPassword(gridMgr.getPassword());
        		user.setSalt(gridMgr.getSalt());
        	}
        }else if("5".equals(roleId)){
        	//企业用户登录
        	CompanyUser comUser = comUserMp.selectByUsername(userName);
        	if(comUser!=null){
        		user = new User();
        		user.setUsername(comUser.getUsername());
        		user.setMobile(comUser.getMobile());
        		user.setId(comUser.getId());
        		user.setPassword(comUser.getPassword());
        		user.setSalt(comUser.getSalt());
        	}
        }
//        User user = this.userService.selectByUsername(username);

        if (user != null) {
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userName, user.getPassword(),ByteSource.Util.bytes(user.getSalt()),this.getName());

            com.itmuch.core.util.User currUser = new com.itmuch.core.util.User();
            currUser.setUsername(user.getUsername());
            currUser.setMobile(user.getMobile());
            currUser.setId(user.getId());

            this.setSession(SessionConstants.USER, currUser);

            return info;
        } else {
            return null;
        }

    }

    /**
     * 设置session
     * @param key key
     * @param value value
     */
    private void setSession(Object key, Object value) {
        Subject currentUser = SecurityUtils.getSubject();
        if (null != currentUser) {
            Session session = currentUser.getSession();
            if (null != session) {
                session.setAttribute(key, value);
            }
        }
    }

    /**
     * 参考文档: http://www.tuicool.com/articles/rEvqym
     * 参考文档: http://sishuok.com/forum/blogPost/list/7461.html
     * 参考文档: http://m.blog.csdn.net/blog/LHacker/19340757
     */
    public void clearCache() {
        Subject subject = SecurityUtils.getSubject();
        super.clearCachedAuthorizationInfo(subject.getPrincipals());
    }

    /**
     * 通过身份信息, 清空该用户的权限缓存
     * 参考: http://m.blog.csdn.net/blog/LHacker/19340757
     * @param principle 身份信息
     */
    public void clearAuthorizationCacheByPrinciple(String principle) {
        String cacheName = this.getAuthorizationCacheName();
        Cache<Object, Object> cache = this.getCacheManager().getCache(cacheName);

        Set<Object> keys = cache.keys();
        if (CollectionUtils.isNotEmpty(keys)) {
            for (Object key : keys) {
                SimplePrincipalCollection spc = (SimplePrincipalCollection) key;
                if (principle.equals(spc.toString())) {
                    cache.remove(key);
                    break;
                }
            }
        }

    }
}
           

ShiroVertifyRealm类

package com.jusfoun.socialgrid.shiro;

import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.itmuch.core.constants.SessionConstants;
import com.itmuch.core.util.SubjectUtil;
import com.jusfoun.socialgrid.admin.domain.CommissionUser;
import com.jusfoun.socialgrid.admin.domain.User;
import com.jusfoun.socialgrid.admin.persistence.CommissionUserMapper;
import com.jusfoun.socialgrid.admin.service.RoleService;
import com.jusfoun.socialgrid.admin.service.UserService;
import com.jusfoun.socialgrid.gridManager.domain.GridManager;
import com.jusfoun.socialgrid.gridManager.persistence.GridManagerMapper;

public class ShiroVertifyRealm  extends AuthorizingRealm{

	final static Logger LOGGER = LoggerFactory.getLogger(ShiroVertifyRealm.class);  
	@Resource
    private UserService userService;
    @Resource
    private RoleService roleService;
    @Autowired
    public GridManagerMapper gridMp;
    @Autowired
    public CommissionUserMapper commMp;
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		 SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();

	        // 1. 通过用户id,查询用户具有的角色(查询sys_admin_role)
	        Long id = SubjectUtil.getUser().getId();
	        // 如果是超级管理员, 则拥有所有权限, 不受角色约束
	        List<String> permissions = null;
	        if (1L == id) {
	            permissions = this.userService.selectAllPermissions();
	        }
	        // 并非超管
	        else {
	            List<Long> roleIds = this.userService.selectRoleIdListByUserId(id);
	            if ((roleIds != null) && !roleIds.isEmpty()) {
	                // 2. 通过角色id, 查询角色具有的权限
	                permissions = this.userService.selectPermissionsByRoleIds(roleIds);

	            }
	        }
	        if ((permissions != null) && !permissions.isEmpty()) {
	            auth.addStringPermissions(permissions);
	            return auth;
	        }
	        return null;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
		UsernamePasswordCaptchaToken token = (UsernamePasswordCaptchaToken)authenticationToken;
		String userName = token.getUsername();
        LOGGER.info("用户:{}尝试登陆.", userName);
        String roleId = (String)SecurityUtils.getSubject().getSession().getAttribute("role_id");
     // 增加判断验证码逻辑
        String captcha = token.getCaptcha();
        String verCode = (String)SecurityUtils.getSubject().getSession().getAttribute("loginCode");
        if (null == captcha || !captcha.equals(verCode)) {
			throw new CaptchaException("验证码错误");
		}
        User user = null;
        if("1".equals(roleId)){
        	user = this.userService.selectByUsername(userName);
        }else if("2".equals(roleId)){
        	//委办局人员登录
        	List<CommissionUser> list = commMp.selectCommByName(userName);
        	if(list!=null&&list.size()!=0){
        		CommissionUser commUser = list.get(0);
        		user = new User();
        		user.setUsername(commUser.getUsername());
        		user.setMobile(commUser.getMobile());
        		user.setId(commUser.getId());
        		user.setPassword(commUser.getPassword());
        		user.setSalt(commUser.getSalt());
        	}
        }else if("3".equals(roleId)||"4".equals(roleId)){
        	//网格长和网格员登录
        	List<GridManager> list = gridMp.selectGridMgrByName(userName);
        	if(list!=null&&list.size()!=0){
        		GridManager gridMgr = list.get(0);
        		user = new User();
        		user.setUsername(gridMgr.getUsername());
        		user.setMobile(gridMgr.getMobile());
        		user.setId(gridMgr.getId());
        		user.setPassword(gridMgr.getPassword());
        		user.setSalt(gridMgr.getSalt());
        	}
        }
        
//        User user = this.userService.selectByUsername(userName);

        if (user != null) {
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userName, user.getPassword(), ByteSource.Util.bytes(user.getSalt()),
                    this.getName());

            com.itmuch.core.util.User currUser = new com.itmuch.core.util.User();
            currUser.setUsername(user.getUsername());
            currUser.setMobile(user.getMobile());
            currUser.setId(user.getId());

            this.setSession(SessionConstants.USER, currUser);

            return info;
        } else {
            return null;
        }
	}
	 /**
     * 设置session
     * @param key key
     * @param value value
     */
    private void setSession(Object key, Object value) {
        Subject currentUser = SecurityUtils.getSubject();
        if (null != currentUser) {
            Session session = currentUser.getSession();
            if (null != session) {
                session.setAttribute(key, value);
            }
        }
    }
    /**
     * 参考文档: http://www.tuicool.com/articles/rEvqym
     * 参考文档: http://sishuok.com/forum/blogPost/list/7461.html
     * 参考文档: http://m.blog.csdn.net/blog/LHacker/19340757
     */
    public void clearCache() {
        Subject subject = SecurityUtils.getSubject();
        super.clearCachedAuthorizationInfo(subject.getPrincipals());
    }

    /**
     * 通过身份信息, 清空该用户的权限缓存
     * 参考: http://m.blog.csdn.net/blog/LHacker/19340757
     * @param principle 身份信息
     */
    public void clearAuthorizationCacheByPrinciple(String principle) {
        String cacheName = this.getAuthorizationCacheName();
        Cache<Object, Object> cache = this.getCacheManager().getCache(cacheName);

        Set<Object> keys = cache.keys();
        if (CollectionUtils.isNotEmpty(keys)) {
            for (Object key : keys) {
                SimplePrincipalCollection spc = (SimplePrincipalCollection) key;
                if (principle.equals(spc.toString())) {
                    cache.remove(key);
                    break;
                }
            }
        }

    }
//自定义认证授权,替代默认的用户名密码验证
	@Override
	protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)
			throws AuthenticationException {
		UsernamePasswordCaptchaToken captchaToken = (UsernamePasswordCaptchaToken)token;
		if(!captchaToken.getUsername().equals(info.getPrincipals().toString())){
			String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
            throw new IncorrectCredentialsException(msg);
		}
	}

}
           

UsernamePasswordCaptchaToken类

package com.jusfoun.socialgrid.shiro;

import org.apache.shiro.authc.UsernamePasswordToken;

public class UsernamePasswordCaptchaToken  extends UsernamePasswordToken{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * 验证码
	 */
	private String captcha;
	 /** 
     * 用户名 
     */  
    private String username;  
  
    /** 
     * 密码, in char[] format 
     */  
    private char[] password;  
    /** 
     * 主机名称或ip 
     */  
    private String host; 
  
    /** 
     * 是否记住我 
     * 默认值:<code>false</code> 
     */  
    private boolean rememberMe = false;  
  
    
    /**
     * 构造方法
     * @param captcha验证码
     * @param username用户名
     */
    public UsernamePasswordCaptchaToken(String username,String captcha) {
		super();
		this.captcha = captcha;
		this.username = username;
	}

	public String getCaptcha() {
		return captcha;
	}

	public void setCaptcha(String captcha) {
		this.captcha = captcha;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public char[] getPassword() {
		return password;
	}

	public void setPassword(char[] password) {
		this.password = password;
	}

	public void setRememberMe(boolean rememberMe) {
		this.rememberMe = rememberMe;
	}


	public void setHost(String host) {
		this.host = host;
	}

	@Override
	public Object getPrincipal() {
		return getUsername();
	}

	@Override
	public Object getCredentials() {
		return getPassword();
	}

	@Override
	public boolean isRememberMe() {
		// TODO Auto-generated method stub
		return rememberMe;
	}

	@Override
	public String getHost() {
		return host;
	}
}