shiro在项目中的使用(一)

【前言】
Apache Shiro是Java的一个安全框架。主要用于权限控制,简单易用。之前单看shiro始终理会不了它的思想,后来在网上发现某智的一个bos项目中运用到了shiro,果断学习,看完后略有心得,以记之。

【项目简介】
该bos项目主要是一个后台管理项目,采用传统ssh技术架构,使用spring与shiro进行整合做权限拦截,以下是项目中权限部分的笔记。

首先,我们从外部来看Shiro吧,即从应用程序角度的来观察如何使用Shiro完成工作

shiro工作流程.png
Subject:主体,代表了当前“用户”

SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互

Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限)

用户主体访问系统,由安全管理器进行权限验证,安全管理器从Realm域中获取到该用户的角色权限,并作出相应的权限反馈,Realm域就是一个Dao,主要获取用户的角色权限数据并交给安全管理器。所以整个流程中,安全管理器是核心角色。

【1】web.xml中配置shiro的过滤器
shiro的过滤器就类似于struts2的核心过滤器一般

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

注意:这里filterName的值可以随便起,无要求。但是在spring注入时要保持一致

【2】将shiro过滤器注入spring

<!-- 配置工厂bean,用于创建shiro框架用到过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 注入安全管理 -->
        <property name="securityManager" ref="securityManager"></property>
        <!-- 注入当前系统的登录页面 -->
        <property name="loginUrl" value="/login.jsp"></property>
        <!-- 注入成功页面 -->
        <property name="successUrl" value="/index.jsp"></property>
        <!-- 注入权限不足页面 -->
        <property name="unauthorizedUrl" value="/unauthorizedUrl.jsp"/>
        <!-- 注入url拦截规则 -->
        <property name="filterChainDefinitions">
            <value>
                /css/** = anon
                /images/** = anon
                /js/** = anon
                /login.jsp* = anon
                /validatecode.jsp* = anon
                /userAction_login.action = anon
                /page_base_staff.action = perms["staff"]<!-- roles角色集,perms权限集 -->
                /* = authc
            </value>
            <!-- 
                /page_base_staff.action = roles["staff"]//要访问此action必须有staff这个角色
                /page_base_staff.action = perms["staff"]//要访问此action必须有staff这个权限
             -->
        </property>
    </bean>

注意:以上属性均以set注入,查看ShiroFilterFactoryBean源码便知,业务需要配哪个属性就配哪个,非必要配置,这里页面以/开头均在webroot目录下。

这里bean 的id属性要与web.xml中shiro的过滤器名称一致

url拦截规则:一般图片、JS、CSS样式不拦截,直接设置anon角色权限即可(/css/** = anon)
具体url拦截:
    /page_base_staff.action = perms["staff"]//访问此action需要staff权限
    /page_base_staff.action =roles["staff"]//访问此action需要staff角色(角色是权限的集合)

要拦截的路径:/* = authc

【3】编写自定义Realm域并注入到spring中
自定义Realm需要继承AuthorizingRealm,实现其认证 授权方法

/**
 * ClassName: BOSRealm
 * @author lvfang
 * @Desc: 自定义realm
 * @date 2017-8-23
 */
public class BOSRealm extends AuthorizingRealm {
    
    @Resource
    private IUserDao userDao;
    
    /**
     * 认证方法(是否有这个用户)
     */
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        System.out.println("进入认证方法... ...");
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;//token令牌强转
        String username = upToken.getUsername();//从令牌中得到用户名
        
        //查询用户
        User user = userDao.findUserByUsername(username);
        if(user == null){
            //用户名不存在
            return null;
        }else{
            //用户名存在
            String password = user.getPassword();
            
            // 创建简单认证信息对象
            /***
             * 参数一:签名,程序可以在任意位置获取当前放入的对象
             * 参数二:从数据库中查询出的密码
             * 参数三:当前realm的名称
             */
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,password,this.getClass().getSimpleName());
            //返回给安全管理器,由安全管理器负责比对数据库中查询出的密码和页面提交的密码
            return info;
        }   
    }

    /**
     * 授权方法(这个用户有什么权限)
     */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("进入授权方法... ...");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("staff");//为当前用户授予staff权限
        info.addRole("staff");//为当前用户授予staff角色(角色是权限的集合)    
        //TODO 根据当前登录用户查询数据库,获取其对应的权限数据
        
        return info;
    }
}

注入spring

<!-- 注册自定义realm -->
    <bean id="bosRealm" class="com.itheima.bos.shiro.BOSRealm"></bean>

【4】注入安全管理器,并将realm注入给安全管理器

<!-- 注入 securityManager管理器-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!-- 将自定义realm注入给securityManager管理 -->
        <property name="realm" ref="bosRealm"></property>
    </bean>

【5】在login方法中做处理

/**
     * 登陆方法(shiro版)
     * @return
     */
    public String login(){  
        //判断验证码
        String code = (String) this.setSession("key");
        //判断验证码是否正确
        if(StringUtils.isNotBlank(checkcode)&& checkcode.equals(code)){
            
            //获取当前用户对象
            Subject subject = SecurityUtils.getSubject();//目前为"未认证状态"
            String password = model.getPassword();
            password = MD5Utils.md5(password);
            //构造一个用户名密码令牌
            AuthenticationToken token = new UsernamePasswordToken(model.getUsername(),password);
            
            try {
                subject.login(token);
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                //登陆失败  设置提示信息,跳转登陆页面
                this.addActionError("用户名不存在!");
                return "login";
            } catch (Exception e) {
                e.printStackTrace();
                //登陆失败  设置提示信息,跳转登陆页面
                this.addActionError("用户名或密码错误!");
                return "login";
            }
            
            //获取认证信息对象中存储的User对象
            User user = (User) subject.getPrincipal();
            this.getSession().setAttribute("loginUser", user);//用户存入session
            return "home";
        }else{
            //登陆失败,验证码失败 跳转至登陆页面
            this.addActionError("验证码错误!");
            return "login";
        }   
    }

这里根据username和password构造一个用户名令牌,当subject主体去调用login()方法登陆时,会执行Realm域中的认证和授权方法。

【附加】

1:
shiro过滤器属性含义

securityManager:这个属性是必须的。

loginUrl :没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。

successUrl :登录成功默认跳转页面,不配置则跳转至”/”。如果登陆前点击的一个需要登录的页面,则在登录自动跳转到那个需要登录的页面。不跳转到此。

unauthorizedUrl :没有权限默认跳转的页面


2:
其权限过滤器及配置释义

anon:例子/admins/**=anon 没有参数,表示可以匿名使用。

authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数

roles(角色):例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。

perms(权限):例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。

rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。

port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString

是你访问的url里的?后面的参数。

authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证

ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https

user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,559评论 18 139
  • 前言 Spring boot 是什么,网上的很多介绍,这里博客就不多介绍了。如果不明白Spring boot是什么...
    xuezhijian阅读 17,890评论 13 39
  • 1.简介 Apache Shiro是Java的一个安全框架。功能强大,使用简单的Java安全框架,它为开发人员提供...
    H_Man阅读 3,150评论 4 48
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,712评论 6 342
  • 雨突然 下得好猛 他没带伞 躲在路边屋檐 发呆 那伞下的姑娘们 行色勿勿 他问 白娘子呀 你眼泪涟涟找啥呢 许仙又...
    雪莉诗话阅读 154评论 1 12