Shiro安全框架与Spring

  1. 引入相关jar包
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-all</artifactId>
    <version>1.3.2</version>
</dependency>
  1. 在web.xml中配置spring框架提供的用于整合shiro框架的过滤器
<!-- 配置spring框架提供的用于整合shiro框架的过滤器,注意放其他过滤器前面 -->
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  1. 在spring配置文件中配置bean,id为shiroFilter
<!-- 配置shiro框架的过滤器工厂对象 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 注入安全管理器对象 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 注入相关页面访问URL -->
        <!-- 注入跳转到登陆的URL,还没登陆情况下 -->
        <property name="loginUrl" value="/login.jsp"/>
        <!-- 注入登陆成功后访问的URL,这个配置可以不配,因为本身登陆逻辑就会跳转到index -->
        <property name="successUrl" value="/index.jsp"/>
        <!-- 注入权限不足时访问的URL -->
        <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
        <!--注入URL拦截规则 -->
        <property name="filterChainDefinitions">
            <value>
                /css/** = anon //anon是匿名访问过滤器,相当于不过滤,不用登陆也可以访问,放行
                /js/** = anon
                /images/** = anon
                /validatecode.jsp* = anon
                /login.jsp = anon
                /userAction_login.action = anon
                /page_base_staff.action = perms["staff-list"] //perms是权限检查过滤器
                /* = authc //这个是框架提供的过滤器的别名,检查当前用户是否认证过
            </value>
        </property>
    </bean>
    <!-- 注册安全管理器对象 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm"/>
    </bean>
    <!-- 注册realm -->
    <bean id="myRealm" class="com.xxx.xxx.realm.MyRealm"></bean>

使用场景一:登陆认证

认证流程
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
//使用shiro框架提供的方式进行认证操作
            Subject subject = SecurityUtils.getSubject();//获得当前用户对象,状态为“未认证”
            AuthenticationToken token = new UsernamePasswordToken(model.getUsername(),MD5Utils.md5(model.getPassword()));//创建用户名密码令牌对象,两个参数为账号和密码
            try{
                subject.login(token);//这个方法会去调SecurityManager,没有返回值,用try catch来判断登陆是否成功
            }catch(Exception e){
                e.printStackTrace();
                return LOGIN;//返回登陆界面
            }
//SecurityManager要去调用Realm,所以要写个Realm,请先看下面的MyRealm代码
            User user = (User) subject.getPrincipal();//把MyRealm里简单认证信息对象取出来
            ServletActionContext.getRequest().getSession().setAttribute("loginUser", user);//存到Session里去
            return HOME;

创建个自定义Realm

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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;


public class MyRealm extends AuthorizingRealm{
    @Autowired
    private UserDao userDao;
    
    //认证方法
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("自定义的realm中认证方法执行了。。。。");
        UsernamePasswordToken passwordToken = (UsernamePasswordToken)token;
        //获得页面输入的用户名
        String username = passwordToken.getUsername();
        //根据用户名查询数据库中的密码
        User user = userDao.findUserByUsername(username);
        if(user == null){
            //页面输入的用户名不存在,认证失败
            return null;
        }
        //简单认证信息对象
        AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
        //框架负责比对数据库中的密码和页面输入的密码是否一致
        return info;
    }

    //授权方法
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
         SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //为用户授权
        info.addStringPermission("staff-list");//"staff-list"对应前面配置的perms权限检查过滤器,在请求对应的url时会去获取权限,具体实现可以根据业务需求展开
        return info;
    }
}

使用场景二:权限控制

注解式权限控制(代理模式)

  1. 在spring配置文件中配置bean
!-- 开启shiro框架注解支持 -->
    <bean id="defaultAdvisorAutoProxyCreator" 
        class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
            <!-- 必须使用cglib方式为Action对象创建代理对象 -->
        <property name="proxyTargetClass" value="true"/>
    </bean>
    
    <!-- 配置shiro框架提供的切面类,用于创建代理对象 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>
  1. 在要控制的方法里加上注解
@RequiresPermissions("domethod")//执行这个方法,需要当前用户具有domethod这个权限
    public String method(){
        return "index";
    }
  1. 需要在表现层配置全局异常处理器
    3.1.0 Struts2全局异常配置(struts.xml)
        <!-- 全局结果集定义 -->
        <global-results>
            <result name="login">/login.jsp</result>
            <result name="unauthorized">/unauthorized.jsp</result>
        </global-results>
        <global-exception-mappings>
            <exception-mapping result="unauthorized" 
                exception="org.apache.shiro.authz.UnauthorizedException"></exception-mapping>
        </global-exception-mappings>

3.2.0 SpringMVC全局异常配置(springmvc.xml)

  <!-- 全局异常处理器 -->
    <bean class="cn.exception.GlobalExceptionResolver"/>

需要自定义一个全局异常处理器,实现HandlerExceptionResolver接口

private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionResolver.class); 
@Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
            //打印控制台
            ex.printStackTrace();
            //写日志
            logger.debug("测试输出的日志。。。。。。。");
            logger.info("系统发生异常了。。。。。。。");
            logger.error("系统发生异常", ex);
            //发邮件、发短信
            //使用jmail工具包。发短信使用第三方的Webservice。
            //显示错误页面
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName("error/exception");
            return modelAndView;
    }

页面标签方式权限控制(标签模式)

  1. 在jsp页面中引入shiro的标签库
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
  1. 使用shiro的标签控制页面元素展示,在要控制权限的元素上
<shiro:hasPermission name="staff-delete">
    {
        id : 'button-delete',
        text : '删除',
        iconCls : 'icon-cancel',
        handler : doDelete
    },
    </shiro:hasPermission>
注:如果没有权限,那么shiro:hasPermission包裹的元素无法展示
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342