前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >shiro整合springmvc

shiro整合springmvc

作者头像
week
发布2018-08-24 15:06:26
1K0
发布2018-08-24 15:06:26
举报
文章被收录于专栏:用户画像

代码:https://github.com/jxq0816/springmvc_framework

参考:http://shiro.apache.org/spring.html

一、pom.xml 加入shiro的dependency

代码语言:javascript
复制
<!-- SECURITY begin -->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>${shiro.version}</version>
    </dependency>

    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-spring</artifactId>
      <version>${shiro.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-cas</artifactId>
      <version>${shiro.version}</version>
      <exclusions>
        <exclusion>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>${shiro.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-ehcache</artifactId>
      <version>${shiro.version}</version>
    </dependency>
    <!-- SECURITY end -->

二、web.xml 配置shiro过滤器

代码语言:javascript
复制
 <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:/spring-context.xml
            classpath:/spring-context-shiro.xml
        </param-value>
    </context-param>

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

三、resources目录下新建spring-context-shiro.xml

代码语言:javascript
复制
<?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.1.xsd"
	default-lazy-init="true">

	<description>Shiro Configuration</description>
	
	<!-- Shiro权限过滤过滤器定义 -->
	<bean name="shiroFilterChainDefinitions" class="java.lang.String">
		<constructor-arg>
			<value>
				/user/login = anon
				/user/logout = anon
				/** = authc
			</value>
		</constructor-arg>
	</bean>
	
	<!-- 安全认证过滤器 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/user/login" />
		<property name="successUrl" value="/user/login" />
		<property name="filterChainDefinitions">
			<ref bean="shiroFilterChainDefinitions"/>
		</property>
	</bean>


	<!-- 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的MyRealm.java -->
	<bean id="myRealm" class="com.week7i.share.security.SystemAuthorizingRealm"/>

	<!-- 定义Shiro安全管理配置 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="myRealm" />
	</bean>

</beans>

四、spring-mvc-dispatcher.xml 前端控制器中加入如下配置,这样可以支持@RequiresRoles的相关权限过滤

代码语言:javascript
复制
 <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证  -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

五、自定义realm

代码语言:javascript
复制
package com.week7i.share.security;

import com.week7i.share.controller.controller;
import com.week7i.share.service.SystemService;
import com.week7i.share.util.SpringContextHolder;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Service;

/**
 * Created by jiangxingqi on 2017/7/19.
 */
@Service
public class SystemAuthorizingRealm extends AuthorizingRealm {

    private static SystemService systemService;

    private static Logger logger = Logger.getLogger(controller.class);

    /**
     * 获取系统业务对象
     */
    public SystemService getSystemService() {
        if (systemService == null){
            systemService = SpringContextHolder.getBean(SystemService.class);
        }
        return systemService;
    }


    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String currentUsername = (String)super.getAvailablePrincipal(principals);
        SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
        if(StringUtils.isNotEmpty(currentUsername)){
            //添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色
            String roleName=systemService.getRoleByUserName(currentUsername);
            if(StringUtils.isNotEmpty(roleName)){
                simpleAuthorInfo.addRole(roleName);
                logger.info("已为用户["+currentUsername+"]赋予了["+roleName+"]角色");
            }
            //添加权限
            //simpleAuthorInfo.addStringPermission("admin:manage");
            return simpleAuthorInfo;
        }
        return simpleAuthorInfo;
    }
    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取基于用户名和密码的令牌
        //实际上这个authcToken是从LoginController里面currentUser.login(token)传过来的
        UsernamePasswordToken authToken = (UsernamePasswordToken)token;
        logger.info("MyRealm.doGetAuthenticationInfo.token="+token);
        //此处无需比对,比对的逻辑Shiro会做,我们只需返回一个和令牌相关的正确的验证信息
        //第一个参数填登录用户名,第二个参数填合法的登录密码
        String username=authToken.getUsername();
        if(StringUtils.isEmpty(username)==false) {
            String password=getSystemService().login(username);
            if(StringUtils.isEmpty(password)==false){
                AuthenticationInfo authInfo = new SimpleAuthenticationInfo(username, password, this.getName());
                return authInfo;
            }
        }
        //没有返回登录用户名对应的SimpleAuthenticationInfo对象时,就会在LoginController中抛出UnknownAccountException异常
        return null;
    }
}

六、controller

代码语言:javascript
复制
package com.week7i.share.controller;

/**
 * Created by jiangxingqi on 2017/2/9.
 */

import com.week7i.share.service.SystemService;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by jiangxingqi on 2017/2/9.
 */
@Controller
@RequestMapping("user")
public class controller {

    private static Logger logger = Logger.getLogger(controller.class);

    @Autowired
    private SystemService service;

    @RequestMapping(value = "index")
    public String index(){
        return "index";
    }

    @RequiresRoles("admin")
    @RequestMapping(value = "back")
    @ResponseBody
    public Map fun(){
        Map map=new HashMap();
        String password=service.login("admin");
        map.put("password",password);
        return map;
    }
    @RequestMapping(value = {"login",""},method= RequestMethod.GET)
    public String login(){
        return "login";
    }

    @RequestMapping(value = {"login"},method= RequestMethod.POST)
    public String loginSubmit(String username,String password,Model model){
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        token.setRememberMe(true);
        logger.debug("DefaultController.login#token="+token);
        Subject currentUser = SecurityUtils.getSubject();
        try {
            //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
            //每个Realm都能在必要时对提交的AuthenticationTokens作出反应
            //所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法
            logger.debug("user[" + username + "]do login checking");
            currentUser.login(token);
            logger.debug("user[" + username + "]authentication success");

        }catch(UnknownAccountException uae){
            logger.debug("user[" + username + "]UnknownAccountException");
            model.addAttribute("error_msg", "UnknownAccountException");
        }catch(IncorrectCredentialsException ice){
            logger.debug("user[" + username + "]IncorrectCredentialsException");
            model.addAttribute("error_msg", "IncorrectCredentialsException");
        }catch(LockedAccountException lae){
            logger.debug("user[" + username + "]LockedAccountException");
            model.addAttribute("error_msg", "LockedAccountException");
        }catch(ExcessiveAttemptsException eae){
            logger.debug("user[" + username + "]ExcessiveAttemptsException");
            model.addAttribute("error_msg", "ExcessiveAttemptsException");
        }catch(AuthenticationException ae){
            //注意:这个必须放在后面,因为这个异常可以处理所有认证失败的情况
            model.addAttribute("error_msg", "authentication faild");
        }
        //验证是否登录成功
        if(currentUser.isAuthenticated()){
            logger.debug("user[" + username + "]authentication success");
            return "index";
        }
        token.clear();
        return "login";
    }
    @RequestMapping("logout")
    public String logout(){
        SecurityUtils.getSubject().logout();
        return "login";
    }
}

六、login.jsp

代码语言:javascript
复制
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${error_msg}
<form action="/user/login" method="POST">
    姓名:<input type="text" name="username"/><br/>
    密码:<input type="password" name="password"/><br/>
    <input type="submit" value="确认"/>
</form>
</body>
</html>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年07月20日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档