• 贼简单的Shiro框架之粗粒度控制菜单栏


     Spring整合Shiro安全框架 ##

    ----------

    ### **Shiro框架的配置**

    ​    

        1. 导入jar包,如果使用了Maven,引入坐标即可(项目配置文件中已经引入)
        2. 配置Spring整合Shiro的核心过滤器,核心filter,一个filter相当于10个filter
            * 代码如下
                <!-- Shiro Security filter  filter-name这个名字的值将来还会在spring中用到  -->
                <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>
        
        3. Spring整合Shiro框架,需要配置
            * 创建applicationContext-shiro.xml的配置文件,引入约束
            * 在applicationContext配置文件引入<import resource="classpath:spring/applicationContext-shiro.xml"></import>
        
        4. 配置DelegatingFilterProxy过滤器,通过shiroFilter名称去IOC的容器中查找对象,配置该对象(配置具体的规则)
            <!-- filter-name这个名字的值来自于web.xml中filter的名字 -->
            <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
                <property name="securityManager" ref="securityManager"/>
                <!--登录页面  -->
                <property name="loginUrl" value="/index.jsp"></property>
                <!-- 登录成功后-->
                <property name="successUrl" value="/home.action"></property>
                
                <property name="filterChainDefinitions">
                    <!-- /**代表下面的多级目录也过滤 -->
                    <value>
                        /index.jsp* = anon
                        /home* = anon
                        /sysadmin/login/login.jsp* = anon
                        /sysadmin/login/loginAction_logout* = anon
                        /login* = anon
                        /logout* = anon
                        /components/** = anon
                        /css/** = anon
                        /img/** = anon
                        /js/** = anon
                        /plugins/** = anon
                        /images/** = anon
                        /js/** = anon
                        /make/** = anon
                        /skin/** = anon
                        /stat/** = anon
                        /ufiles/** = anon
                        /validator/** = anon
                        /resource/** = anon
                        /** = authc   
                        /*.* = authc
                    </value>
                </property>
            </bean>
        
        5. 配置安全管理器,需要配置
            * 配置安全管理器
                <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
                    <!-- 必须要注入自定义Realm域,至少提供一个 -->
                    <property name="realm" ref="authRealm"/>
                </bean>
            
            * 配置自定义Realm域,准备提供数据
                <!-- 配置自定义Realm域 -->
                <bean id="authRealm" class="cn.Mr.Neng.jk.shiro.AuthRealm">
                    <!-- 注入密码比较器  -->
                    <property name="credentialsMatcher" ref="passwordMatcher"/>
                </bean>
                
                * 注意:该Realm域还没有创建,需要自己手动创建,Realm类必须要继承AuthorizingRealm类,这是编写Realm域的规范。就相当于过滤器要实现Filter接口一个道理。
                * 有2个抽象方法必须添加实现,具体的代码如下
                    /**
                     * 自定义Realm域
                     * @author Administrator
                     */
                    public class AuthRealm extends AuthorizingRealm{
                        
                        @Resource(name="userService")
                        private UserService userService;
                        
                        /**
                         * 授权
                         */
                        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
                            return null;
                        }
                        
                        /**
                         * 认证
                         */
                        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
                            return null;
                        }
                    }
            
            * 配置密码比较器的类,密码比较器的类也需要自己手动创建,需要继承SimpleCredentialsMatcher类,重写doCredentialsMatch方法进行密码比较
                * 具体的代码如下
                    /**
                     * 密码比较器
                     * @author Administrator
                     */
                    public class CustomCredentialsMatcher extends SimpleCredentialsMatcher{
                        /**
                         * 用于进行密码比较的
                         */
                        public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
                            
                            return super.doCredentialsMatch(token, info);
                        }
                    }
                
                * 配置如下
                    <bean id="passwordMatcher" class="cn.Mr.Neng.jk.shiro.CustomCredentialsMatcher"/>
        
        6. 测试shiro的配置文件
            * 首先修改LoginAction类的login的方法,添加如下代码
                // 判断用户名是否为空,如果为空,跳转到登录页面
                if(UtilFuns.isEmpty(username)){
                    return LOGIN;
                }

    ----------

    ### **Md5hash加密算法**

    ​    

        1. md5的加密
            * 比较常用的加密算法,相对来说容易被破解
            * 算法比较固定,密码是123,使用md5加密,得到的密文是固定的(202cb962ac59075b964b07152d234b70)!!    
        
        2. 采用shiro的Md5Hash算法进行加密
            * 使用工具类Encrypt类

    ----------

    ### **登录认证的代码编写**

    ​    

        1. 打开AuthRealm类,准备完成认证代码的编写。认证就是登录功能,最疼密码需要一致,先编写密码比较器
        2. 打开CustomCredentialsMatcher类,准备编写代码
            /**
             * 密码比较器
             * @author Administrator
             */
            public class CustomCredentialsMatcher extends SimpleCredentialsMatcher{
                
                /**
                 * 用于进行密码比较的
                 * token -- 表示从页面传过来的用户名和密码
                 * info     -- 表示从数据库中查询到的密码
                 */
                public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
                    // 把token向下强转成实现类
                    UsernamePasswordToken upToken = (UsernamePasswordToken) token;
                    // 获取密码
                    String inputPwd = new String(upToken.getPassword());
                    // 对密码加密
                    String md5Pwd = Encrypt.md5(inputPwd, upToken.getUsername());
                    // 获取到数据库中的密码
                    String dbPwd = info.getCredentials().toString();
                    return super.equals(md5Pwd, dbPwd);
                }
            }
        
        3. 打开AuthRealm类,完成认证的方法编写,具体的代码如下
            /**
             * 认证
             * AuthenticationToken token 表示页面传过来的用户名和密码
             * 逻辑:通过用户名查询数据库,获取到该用户的密码,封装到AuthenticationInfo对象中,返回。
             */
            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            
                UsernamePasswordToken upToken = (UsernamePasswordToken) token;
                // 获取到用户名
                final String username = upToken.getUsername();
                // 创建条件对象
                Specification<User> spec = new Specification<User>() {
                    public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                        return cb.equal(root.get("userName").as(String.class), username);
                    }
                };
                
                // 通过用户名查询数据库,查询数据库,查询数据
                List<User> list = userService.find(spec);
                // 判断
                if(list != null && list.size() > 0){
                    // 获取到user对象
                    User user = list.get(0);
                    
                    // 创建AuthenticationInfo对象
                    /**
                     * principal        user对象
                     * credentials        密码
                     * realmName        字符串,自定义的,realm的名称
                     */
                    SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), "abc");
                    return info;
                }
                return null;
            }

    ----------

    ### **编写登录的方法**

    ​    

        1. 搭建LoginAction,编写login的登录方法,具体代码如下
            public String login() throws Exception {
                // 判断
                if(UtilFuns.isEmpty(username)){
                    return LOGIN;
                }
                try {
                    // 先获取到Subject对象
                    Subject subject = SecurityUtils.getSubject();
                    // 创建UsernamePasswordToken对象,封装用户名和密码
                    UsernamePasswordToken token = new UsernamePasswordToken(username, password);
                    // 使用shiro框架进行校验
                    subject.login(token);
                    // 获取返回的结果
                    User user = (User) subject.getPrincipal();
                    // 存入到session中
                    ServletActionContext.getRequest().getSession().setAttribute(SysConstant.CURRENT_USER_INFO, user);
                    return SUCCESS;
                } catch (Exception e) {
                    e.printStackTrace();
                    super.put("errorInfo", "用户名或者密码错误!!");
                    return "login";
                }
            }

    ----------

    ### **编写退出的方法**

    ​    

        1. 具体的代码如下
            //退出
            public String logout(){
                //删除session
                session.remove(SysConstant.CURRENT_USER_INFO);        
                SecurityUtils.getSubject().logout();
                return "logout";
            }

    ----------

    用户授权的代码编写
    ​    
        1. 授权功能:认证通过后的用户,所拥有的权限。
        2. shiro框架提供和权限有关的标签库
            * <%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>
            * <shiro:hasPermission name="系统首页">,判断认证通过后的用户,是否拥有系统首页的权限?如果该用户拥有系统首页权限,把标签中间的内容显示到页面上。

      3.打开AuthRealm类,完成授权的方法编写,具体的代码如下
            /**
             * 授权
             */
            protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
                // 从AuthenticationInfo中获取到用户对象
                User user = (User) pc.fromRealm(this.getName()).iterator().next();
                List<String> list = new ArrayList<String>();
                // 继续操作,通过对象导航的方式,获取到该用户下的角色,具有哪些权限
                Set<Role> roles = user.getRoles();
                // 遍历,获取到每一个角色对象
                for (Role role : roles) {
                    // 通过角色对象获取到该角色具有的权限
                    Set<Module> modules = role.getModules();
                    for (Module module : modules) {
                        list.add(module.getName());
                    }
                }

         //这个SimpleAuthorizationInfo 对象封装的是授权信息,以后要判断某个方法或者按钮是否拥有权限,只需要用spring提供的对应标签即可(Permissions)
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();    
                info.addStringPermissions(list);
                return info;               
            }

    注意:此随笔是本人在网上借鉴某某机构所得。

    绊倒我的人我让他永远起不来 扶起我的人我让他永远不会倒 混社会不管你有多努力,到最后都是以成败论英雄!
  • 相关阅读:
    Block代码块中使用局部变量注意点
    This application's application-identifier entitlement does not match that of the installed application. These values must match for an upgrade to be allowed.
    iOS实现渐变颜色
    linker command failed with exit code 1 (use -v to see invocation)
    关于SVN的405错误Server sent unexpected return value (405 Method Not Allowed)的解决办法
    提交SVN Working copy locked解决
    FSCalendar使用和注意事项
    c/c++左值和右值
    mysql使用笔记(一)
    解决 ssh 登录到ubuntu server 慢的问题
  • 原文地址:https://www.cnblogs.com/MrNeng/p/9632904.html
Copyright © 2020-2023  润新知