zoukankan      html  css  js  c++  java
  • Shiro使用总结

    背景:本人刚刚把Shiro整合在了SSM架构的项目上,maven做项目管理工具,实现了简单的认证和授权,以及记住我和验证码功能,简单的记录一下;

    需要ssm项目demo的可以看我之前的文章:最简单易懂的Idea搭建SSM项目过程和配置(文末有demo哦)

    寄语:代码改变世界不敢说,活在当下,敲好每一行代码就可以了

    一、引入Shiro依赖

    我用的Shiro版本是1.2.5,刚开始是引入shiro-all的,后来看到官网上强烈建议不要引入shiro-all,而是要按需引入,我觉得相当有道理哇,于是就引入了下面三个依赖。

        <properties>
            <shiro.version>1.2.5</shiro.version>
          </properties>

        <!-- shiro -->
        <!-- shiro核心包 -->
        <dependency>
          <groupId>org.apache.shiro</groupId>
          <artifactId>shiro-core</artifactId>
          <version>${shiro.version}</version>
        </dependency>
        <!-- 添加shiro web支持 -->
        <dependency>
          <groupId>org.apache.shiro</groupId>
          <artifactId>shiro-web</artifactId>
          <version>${shiro.version}</version>
        </dependency>
        <!-- 添加shiro spring整合 -->
        <dependency>
          <groupId>org.apache.shiro</groupId>
          <artifactId>shiro-spring</artifactId>
          <version>${shiro.version}</version>
        </dependency>

    二、在web.xml中添加Shiro过滤器

    此处过滤所有请求,所以filter-mapping中url-pattern设置的是/*

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

    三、配置sping-shiro.xml文件

    在spring的配置文件中引入spring-shiro.xml

        <!--引入spring-shiro-->
        <import resource="spring-shiro.xml"/>

    Shiro配置说明

    Apache Shiro的配置主要分为四部分:

    • 对象和属性的定义与配置
    • URL的过滤器配置
    • 静态用户配置
    • 静态角色配置
    配置Shiro对象

    主要是为了自定义各个Shiro组件,项目比较简单,我只自定义了Relam和记住我功能

        <!--创建shiro的安全管理器的对象-->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="myShiroRealm" />
            <!--声明会话管理器属性-->
            <!--<property name="sessionManager" ref="sessionManager"></property>-->
            <!--声明rememberMe-->
            <property name="rememberMeManager" ref="rememberMeManager"></property>
        </bean>

    自定义Relam和记住我

        <!-- 项目自定义的Realm -->
        <bean id="myShiroRealm" class="com.blueice.shiro.MyShiroRealm">
            <property name="credentialsMatcher" ref="credentialsMatcher"/>
            <property name="cachingEnabled" value="false"/>
        </bean>
        <!--记住我的配置-->
        <!--声明cookie对象-->
        <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
            <constructor-arg value="rememberMe"></constructor-arg>
            <!--只有http的链接才能使用cookie-->
            <property name="httpOnly" value="true"></property>
            <!--cookie的失效时间30天,单位是秒-->
            <property name="maxAge" value="2592000"></property>
        </bean>
        <!--声明记住我的管理器对象-->
        <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
            <property name="cookie" ref="rememberMeCookie"></property>
        </bean>

    配置Shiro过滤器

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager" />
            <property name="loginUrl" value="/login" />
            <property name="successUrl" value="/welcome" />
            <property name="unauthorizedUrl" value="/login" />
            <property name="filters">
                <util:map>
                    <entry key="authc" value-ref="captchaFormAuthenticationFilter"/>
                </util:map>
            </property>
            <property name="filterChainDefinitions">
                <value>
                    /static/**  = anon
                    /plugins/** = anon
                    /kaptcha    = anon
                    /kaptcha/get= anon
                    /login*     = anon
                    /logout     = logout
                    /**         = authc
                    /**         = user
                </value>
            </property>
        </bean>

    本人项目中引入了谷歌开源框架Kaptcha做验证码校验,因此自定义了一个authc的过滤器captchaFormAuthenticationFilter,重写了创建token的方式,加入了验证码字段。

    <!--自定义添加验证码的过滤器-->
    <bean id="captchaFormAuthenticationFilter" class="com.blueice.filter.MyFormAuthenticationFilter"/>

    URL表达式说明

    1、URL目录是基于HttpServletRequest.getContextPath()此目录设置

    2、URL可使用通配符,**代表任意子目录

    3、Shiro验证URL时,URL匹配成功便不再继续匹配查找。所以要注意配置文件中的URL顺序,尤其在使用通配符时。

    Filter Chain定义说明

    1、一个URL可以配置多个Filter,使用逗号分隔

    2、当设置多个过滤器时,全部验证通过,才视为通过

    3、部分过滤器可指定参数,如perms,roles

    Shiro内置的FilterChain

    Filter Name 功能
    anno 不需要授权、登录就可以访问。eg:/login
    authc **需要登录授权才能访问。
    authcBasic Basic HTTP身份验证拦截器
    logout 退出拦截器。退出成功后,会 redirect到设置的/URI
    noSessionCreation 不创建会话连接器
    perms 授权拦截器:perm['user:create']
    port 端口拦截器.eg:port[80]
    rest rest风格拦截器
    roles 角色拦截器。eg:role[administrator]
    ssl ssl拦截器。通过https协议才能通过
    user 用户拦截器。eg:登录后(authc),第二次没登陆但是有记住我(remember)都可以访问。

    四、登录认证

    收集token信息

    /*先把账号密码传入shiro里面的UsernamePasswordToken对象里面*/
    CaptchaToken token = new CaptchaToken(username, pwd, captchaCode, rememberMe);

    提交token信息并处理

        /*创建Subject对象*/
        Subject subject = SecurityUtils.getSubject();

        /*调用subject.login()进行登录*/
        try {
            subject.login(token);
        } catch (UnknownAccountException e) {
            error = "用户名/密码错误!";
        } catch (IncorrectCredentialsException e) {
            error = "用户名/密码错误!";
        } catch (ExcessiveAttemptsException e) {
            error = "登录失败多次,账户锁定10分钟!";
        } catch (CaptchaException e) {
            error = "验证码输入有误!";
        } catch (AuthenticationException e) {
            /*其他错误,比如锁定,如果想单独处理请单独catch处理*/
            System.out.println(e.getMessage());
            error = "未知异常,请联系管理员处理!";
        }

    五、注销用户

    logout()会删除session中的所有信息,完成用户的注销操作。

        Session session = SecurityUtils.getSubject().getSession();
        Subject subject = SecurityUtils.getSubject();
        subject.logout();

    六、授权实现

    本文中通过注解 @RequiresPermissions实现授权

        @RequestMapping("/test")
        @ResponseBody
        @RequiresPermissions("user:role:tes")
        public String testMap() {
            Map<String, String> map = indexService.testMap();
            return map.toString();
        }

    七、自定义Relam

    Relam是Shiro的三大核心(SubjectSecurityManagerRelam)之一,通过集成AuthorizingRelam实现自定义Relam,重写了授权信息的doGetAuthorizationInfo方法和认证信息的doGetAuthenticationInfo方法。

        public class MyShiroRealm extends AuthorizingRealm {

        }

    认证实现

    Relam会根据上文login()方法提供的token进行认证

         @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
            String username = token.getUsername();

            SysUser user = null;
            if (username != null  && !"".equals(username)) {
                user = indexService.selectUserInfoByUsername(username);
            }
            if (null == user) {
                /*没找到帐号*/
                throw new UnknownAccountException("用户信息不存在!");
            }
            if (user.getStatus() == 0) {
                /*用户被停用*/
                throw new LockedAccountException("用户信息已被停用");
            }

            ByteSource salt = ByteSource.Util.bytes(user.getUsername());
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(token.getPrincipal(), user.getPassword(),
                     salt, getName());
            return info;
        }

    授权实现

    获取数据库中当前登录用户的权限列表,跟@RequiresPermissions的进行比对,看用户是否有此授权,此处为了方便起见,直接设置了权限为"user:role:test",更多权限一般用逗号分隔。

        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            String userName = (String)principals.getPrimaryPrincipal();
            /*用户权限列表*/
            Set<String> permsSet = new HashSet<>();
            permsSet.add("user:role:test");

            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            authorizationInfo.setStringPermissions(permsSet);

            return authorizationInfo;
        }

    结语

    我是通过Md2All进行排版的,但是代码中//注释会读不到换行,导致后面全部被当成注释,所以我换成了/**/注释;
    Md2All中的代码样式,如果是黑色背景,到了博客园都会变得很难看,最后我选了个白色背景的!
    以上是我此次Shiro使用的总结,互相学习,多多交流哈!

  • 相关阅读:
    解决安装mysql时出现的三种问题
    解决fences2.01在win8.1的状态下无法移动桌面图标问题
    利用Xshell5从本机上向Linux(虚拟机中)上传文件
    PHP加密解密函数(带有效期,过了有效期也解不了)
    js检查身份证号是否正确
    JS中事件绑定函数,事件捕获,事件冒泡
    js获取元素宽高、位置相关知识汇总
    JS中让新手倍感震惊、违反直觉、出乎意料、的一些知识点汇总记录
    Hbuilder工具使用
    HTML、CSS、JS中常用的东西在IE中兼容问题汇总
  • 原文地址:https://www.cnblogs.com/steveshao/p/13645417.html
Copyright © 2011-2022 走看看