shiro与springMVC的整合

1,第一步,在web.xml文件中配置shiro拦截器,以保证要做权限的请求都能被拦截。

<!-- SHIRO过滤器 排在第一位 -->
	<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>

2,单独生成一个shiro-context.xml文件以便管理。(web.xml中本地上下文配置如下:)

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath*:service-context.xml,classpath*:shiro-context.xml,classpath*:quartz-spring.xml</param-value>
	</context-param>
	<context-param>
		<param-name>webAppRootKey</param-name>
		<param-value>momo.web.root</param-value>
	</context-param>
	<context-param>
		<param-name>log4jConfigLocation</param-name>
		<param-value>WEB-INF/log4j.properties</param-value>
	</context-param>
shiro文件详情如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<description>Shiro Configuration</description>
	
	<bean id="webRealm" class="cn.eeye.shiro.WebRealm">
		<property name="userService" ref="userService" />
		<property name="functionService" ref="functionService" />  
	</bean>
	<!--session管理器 -->
	<bean id="defaultWebSessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<property name="sessionDAO" ref="shiroSessionDao" /> 
	</bean>
	
	<bean id="shiroSessionDao" class="cn.eeye.shiro.dao.ShiroSessionDao">
		<property name="shiroSessionRepository" ref="shiroSessionRepository" />
	</bean>
	
	
	<bean id="shiroSessionRepository" class="cn.eeye.shiro.repository.impl.JedisShiroSessionRepository">
		<property name="redisClient" ref="client" />
	</bean>
	
	<!--缓存管理器 -->
	<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"/>
	
	<!-- 安全管理器 注入session与缓存管理器-->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="sessionManager" ref="defaultWebSessionManager"/>
		<property name="cacheManager" ref="cacheManager"/>
		<property name="realm" ref="webRealm" />
	</bean>
	<!-- 生命周期管理器 -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
	
	<!-- web过滤器 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/login/init" />
		<property name="successUrl" value="login/index" />
		<property name="unauthorizedUrl" value="/login/error" />
		<property name="filters">
            <util:map>
                <entry key="authc">
                    <!-- <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/> -->
                    <bean class="cn.eeye.shiro.filter.MomoPassThruAuthenticationFilter"/>
                </entry>
                <!-- <entry key="perms">
                	<bean class="cn.eeye.shiro.filter.UrlPermissionFilter"/>
                </entry> -->
            </util:map>
        </property>
        <!-- 声明路径与过滤器的关系 -->
		<property name="filterChainDefinitions">
			<value> 
			    /login/** = anon
			    /app/** = anon
			    /product/** = anon
			    /userProtocol/** = anon
				/resources/** = anon
				/WEB-INF/views/error/error_404.jsp = anon
				/WEB-INF/views/error/error_500.jsp = anon
				/mobile/** = anon
				/** = authc
            </value>
		</property>
	</bean>
</beans>
web.xml配置通过filter-name:shiroFilter从容器中找到对应的拦截器进行处理(filter-name 需与bean的id一致)。

3,登录认证关键代码:

 @ResponseBody
    @RequestMapping(value = "/index")
    public JsonResponse login(User user, String _cmd, HttpServletRequest request) throws Exception {
        Integer ROLE_CODE = 1;
        user.setUserName(user.getUserName().toUpperCase());
        String password = user.getPassword();
        password = CommonUtils.getMD5(user.getPassword());
        ShiroToken token = new ShiroToken(user.getUserName(), password, ROLE_CODE, false);
        token.setHost(request.getRemoteHost());
        token.setRememberMe(false);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
        } catch (UnknownAccountException uae) {
            logger.info(String.format("who %s , where %s , warn : %s", token.getUsername(), token.getHost(), uae));
            return ajaxFailure("用户名或密码错误,请重试。");
        } catch (LockedAccountException lae) {
            logger.warn(String.format("who %s , where %s , warn : %s", token.getUsername(), token.getHost(), lae));
            return ajaxFailure("您的帐号已被停用,请联系管理员!");
        } catch (ExpiredException ee) {
            logger.warn(String.format("who %s , where %s , warn : %s", token.getUsername(), token.getHost(), ee));
            return ajaxFailure("您的帐号已过期,请联系管理员!");
        } catch (IpBindingException ibe) {
            logger.warn(String.format("who %s , where %s , warn : %s", token.getUsername(), token.getHost(), ibe));
            return ajaxFailure("您的帐号已绑定IP,请在绑定的电脑上登录!");
        } catch (Exception e) {
            logger.info(String.format("who %s , where %s , warn : %s", token.getUsername(), token.getHost(), e));
            return ajaxFailure("用户名或密码错误,请重试。");
        }
        
        // 默认shiro使用request.getSession
        User user_ = this.userService.findUserByUsername(user.getUserName());
        List<Function> functions = this.functionService.findFunctionsByUser(user_.getUserId());
        
        //如果没有授权功能,则没有给用户绑定角色
        if(!"ADMIN".equals(user_.getUserName().toUpperCase()) 
        		&& (functions == null || functions.isEmpty())){
            return ajaxFailure("用户未绑定角色,请联系管理员!");
        }
        
        this.saveLoginLog(user_.getUserId(), request.getRemoteAddr(), Constants.SYS_LOGIN_TYPE1);
        
        subject.getSession(false).setAttribute("principals", user_);
        subject.getSession(false).setTimeout(Constants.REDIS_SESSION_TIMEOUT);
        return ajaxSuccess(ShiroEncryption.decryptionURL(ROLE_CODE, ShiroEncryption.SUCCESS));
    }
    
其中 shiroToken.java代码如下:

public class ShiroToken extends UsernamePasswordToken {

    private static final long serialVersionUID = 1L;

    private Integer ROLE_CODE = null;

    public ShiroToken(String loginName, String password, Integer ROLE_CODE, boolean flag) {
        super(loginName, password, flag);
        this.ROLE_CODE = ROLE_CODE;
    }

    public Integer getROLE_CODE() {
        return ROLE_CODE;
    }

}
subject.login 方法被调用,实际进入的是webReam.java文件中的认证方法。

webrealm文件内容如下:


public class WebRealm extends AuthorizingRealm {
	
	private UserService userService;

	private FunctionService functionService;

	public WebRealm() {
        setName("WebRealm");
    }

    public void setUserService(UserService userService){
    	this.userService = userService;
    }
    
    public void setFunctionService(FunctionService functionService) {
		this.functionService = functionService;
	}
    
    /**
     * 授权方法
     * 
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) throws AuthorizationException {
        String userName = (String) principals.fromRealm(getName()).iterator().next();
        User user = new User();
        user.setUserName(userName);
        try {
            user = this.userService.findUserByUsername(user.getUserName());
        } catch (Exception e) {
            throw new AuthorizationException();
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        if("ADMIN".equalsIgnoreCase(userName)){
        	info.addRole("admin");
        }else{
        	info.addRole("commonUser");
        }
        
        List<Function> functions = this.functionService.findFunctionsByUser(user.getUserId());
        if(functions != null){
        	for(Function function : functions){
        		info.addStringPermission(function.getFunctionCode());
        	}
        }
        
        return info;
    }

    /**
     * 认证方法
     * 
     * @return
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
        ShiroToken token = (ShiroToken) authcToken;
        User user = new User();
        user.setUserName(token.getUsername());
        user.setPassword(String.valueOf(token.getPassword()));
        try {
            user = this.userService.findUserByUsernameAndPassword(user.getUserName(), user.getPassword());
        } catch (Exception e) {
        	e.printStackTrace();
            throw new AuthenticationException();
        }
        if (user != null) {
            if (!Constants.DICT_USER_STATUS_NORMAL.equals(user.getStatus())) {
                throw new LockedAccountException();
            }else if(user.getEndTime() != null && user.getEndTime().before(new Date())){
            	throw new ExpiredException();
            }else if(StringUtils.isNotBlank(token.getHost()) && StringUtils.isNotBlank(user.getIpBinding())
            		&& user.getIpBinding().indexOf(token.getHost()) == -1){
            	throw new IpBindingException();
            }else{
                return new SimpleAuthenticationInfo(user.getUserName(), user.getPassword(), getName());
            }
        } else {
            throw new UnknownAccountException();
        }
    }
}
认证方法处理登录逻辑。并抛出多类型异常。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值