zoukankan      html  css  js  c++  java
  • shiro权限登录案例

    shiro登录案例

    流程:从登陆页面访问进入controller,获取对象主体,在shiro.config中配置过滤器工厂(getShiroFilterFactoryBean),这里进行系统资源配置,注册安全管理器,注册自定义realm,进行md5加密,配置shiro缓存,在realm中,配置认证器、授权器,但是登陆首先是使用认证器,密码使用md5,并且加盐处理,与数据库账号密码匹配。验证成功,重定向到index.jsp,当访问页面时,重新被拦截,授权器拿到登陆后的用户信息,通过用户id去查找该用户对应的角色,通过该角色查询相应的权限,结果返回给授权器,index.jsp根据查询到的权限资源,如果权限有则显示,没有则不显示。

    数据库

    /*
    Navicat MySQL Data Transfer
    
    Source Server         : localHost
    Source Server Version : 50726
    Source Host           : localhost:3306
    Source Database       : shiro
    
    Target Server Type    : MYSQL
    Target Server Version : 50726
    File Encoding         : 65001
    
    Date: 2020-12-18 17:00:47
    */
    create database `shiro` character set utf8;
    
    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for t_perms
    -- ----------------------------
    DROP TABLE IF EXISTS `t_perms`;
    CREATE TABLE `t_perms` (
      `id` int(6) NOT NULL AUTO_INCREMENT,
      `name` varchar(80) DEFAULT NULL,
      `url` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_perms
    -- ----------------------------
    INSERT INTO `t_perms` VALUES ('1', 'user:*:*', '');
    INSERT INTO `t_perms` VALUES ('2', 'product:*:01', null);
    INSERT INTO `t_perms` VALUES ('3', 'order:*:*', null);
    
    -- ----------------------------
    -- Table structure for t_role
    -- ----------------------------
    DROP TABLE IF EXISTS `t_role`;
    CREATE TABLE `t_role` (
      `id` int(6) NOT NULL AUTO_INCREMENT,
      `name` varchar(60) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_role
    -- ----------------------------
    INSERT INTO `t_role` VALUES ('1', 'admin');
    INSERT INTO `t_role` VALUES ('2', 'user');
    INSERT INTO `t_role` VALUES ('3', 'product');
    
    -- ----------------------------
    -- Table structure for t_role_perms
    -- ----------------------------
    DROP TABLE IF EXISTS `t_role_perms`;
    CREATE TABLE `t_role_perms` (
      `id` int(6) NOT NULL,
      `roleid` int(6) DEFAULT NULL,
      `permsid` int(6) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_role_perms
    -- ----------------------------
    INSERT INTO `t_role_perms` VALUES ('1', '1', '1');
    INSERT INTO `t_role_perms` VALUES ('2', '1', '2');
    INSERT INTO `t_role_perms` VALUES ('3', '2', '1');
    INSERT INTO `t_role_perms` VALUES ('4', '3', '2');
    INSERT INTO `t_role_perms` VALUES ('5', '1', '3');
    
    -- ----------------------------
    -- Table structure for t_user
    -- ----------------------------
    DROP TABLE IF EXISTS `t_user`;
    CREATE TABLE `t_user` (
      `id` int(6) NOT NULL AUTO_INCREMENT,
      `username` varchar(40) DEFAULT NULL,
      `password` varchar(40) DEFAULT NULL,
      `salt` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_user
    -- ----------------------------
    INSERT INTO `t_user` VALUES ('1', 'xiaochen', 'ca9f1c951ce2bfb5669f3723780487ff', 'IWd1)#or');
    INSERT INTO `t_user` VALUES ('2', 'zhangsan', 'ca9f1c951ce2bfb5669f3723780487ff', 'IWd1)#or');
    INSERT INTO `t_user` VALUES ('3', 'apple', '9bb1eb6cec8c67bad76436f7610f68af', 'FNLwK00X');
    INSERT INTO `t_user` VALUES ('4', 'apple', '962831c7c6c7a4a2fee3341ae164d448', '$8Uka!yM');
    
    -- ----------------------------
    -- Table structure for t_user_role
    -- ----------------------------
    DROP TABLE IF EXISTS `t_user_role`;
    CREATE TABLE `t_user_role` (
      `id` int(6) NOT NULL,
      `userid` int(6) DEFAULT NULL,
      `roleid` int(6) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_user_role
    -- ----------------------------
    INSERT INTO `t_user_role` VALUES ('1', '1', '1');
    INSERT INTO `t_user_role` VALUES ('2', '2', '2');
    INSERT INTO `t_user_role` VALUES ('3', '2', '3');

    依赖配置

      pom.xml中,引入shiro和ehcache相关依赖

    <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.demo</groupId>
        <artifactId>shiro-demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>war</packaging>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.9.RELEASE</version>
        </parent>
    
        <!-- 配置web依赖 jar -->
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- 内嵌tomcat配置 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <scope>provided</scope>
            </dependency>
            <!-- servlet和jsp的依赖 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-jasper</artifactId>
            </dependency>
            <!-- mysql支持 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.21</version>
            </dependency>
    
            <!-- 数据库连接池 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.6</version>
            </dependency>
            <!-- mybatis框架 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.2</version>
            </dependency>
            <!-- 热部署,不重启启动就更新项目 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <optional>true</optional><!-- true代表热部署生效 -->
            </dependency>
            <!-- lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.18</version>
                <scope>provided</scope>
            </dependency>
            <!--引入shiro整合springboot依赖 -->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring-boot-starter</artifactId>
                <version>1.5.3</version>
            </dependency>
            <!--引入shiro和ehcache -->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-ehcache</artifactId>
                <version>1.5.3</version>
            </dependency>
        </dependencies>
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>

    文件配置

      包含端口配置8080,访问路径/shiro,连接池的配置,实体取别名(这里在xml中,resultType就不用写全路径名字了),mapper映射配置

    server.port=8080
    #web-context
    server.context-path=/shiro
    #页面访问路径
    spring.mvc.view.prefix=/
    spring.mvc.view.suffix=.jsp
    
    #连接池配置
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=UTF-8
    spring.datasource.username=root
    spring.datasource.password=root
    
    #实体取别名
    mybatis.type-aliases-package=com.demo.entity
    #mapper配置
    mybatis.mapper-locations=classpath:com/mapper/*.xml

    启动类

      启动类要注意,main方法中是本类的.class,同时这个类也是启动springboot整个项目的启动类

    package com.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.boot.web.servlet.ServletComponentScan;
    import org.springframework.boot.web.support.SpringBootServletInitializer;
    
    //容器启动配置类
    @SpringBootApplication
    @ServletComponentScan
    public class SpringbootApplication extends SpringBootServletInitializer{
    
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
            return builder.sources(SpringbootApplication.class);
        }
        
        public static void main(String[] args) {
            SpringApplication.run(SpringbootApplication.class, args);
        }
    }

    一般工程目录结构

    实体类

    Role.java

    //角色
    @Data
    @Accessors(chain = true)
    @AllArgsConstructor
    @NoArgsConstructor
    public class Role implements Serializable {
        private String id;
        private String name;
        //定义权限的集合
        private List<Perms> perms;
    }

    User.java

    //用户
    @Data
    @Accessors(chain = true)
    @AllArgsConstructor
    @NoArgsConstructor
    public class User implements Serializable {
        private String  id;
        private String username;
        private String password;
        private String salt;
    
        //定义角色集合
        private List<Role> roles;
    }

    Param.java

    //权限
    @Data
    @Accessors(chain = true)
    @AllArgsConstructor
    @NoArgsConstructor
    public class Perms implements Serializable {
        private String id;
        private String name;
        private String url;
    }

    业务层

    service.java,serviceImpl.java

    public interface UserService {
        //注册用户方法
        void register(User user);
    
        //根据用户名查询业务的方法
        User findByUserName(String username);
    
        //根据用户名查询所有角色   
        User findRolesByUserName(String username);
    
        //根据角色id查询权限集合
        List<Perms> findPermsByRoleId(String id);
    }
    

    @Service(
    "userService") @Transactional public class UserServiceImpl implements UserService { //这里又封装了一dao层 @Autowired private UserDAO userDAO; //通过角色id获取权限列表集合 @Override public List<Perms> findPermsByRoleId(String id) { return userDAO.findPermsByRoleId(id); } //通过用户名拿角色 @Override public User findRolesByUserName(String username) { return userDAO.findRolesByUserName(username); } //通过用户名拿用户 @Override public User findByUserName(String username) { return userDAO.findByUserName(username); } //注册业务 @Override public void register(User user) { //处理业务调用dao //1.生成随机盐 String salt = SaltUtils.getSalt(8); //2.将随机盐保存到数据 user.setSalt(salt); //3.明文密码进行md5 + salt + hash散列 Md5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024); user.setPassword(md5Hash.toHex()); userDAO.save(user); } }

    UserDao.java

    @Mapper
    public interface UserDAO {
        void save(User user);
        User findByUserName(String username);
        //根据用户名查询所有角色
        User findRolesByUserName(String username);
        //根据角色id查询权限集合
        List<Perms> findPermsByRoleId(String id);
    }

    UserDAOMapper.xml

       这里使用了一对多的关系,collection连接表。通过用户名获取角色集合,通过角色获取权限的id

    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.demo.dao.UserDAO">
        <!-- 注册用户 
        useGeneratedKeys="true" keyProperty="id"
        这个配置可以在增加一条数据后,直接获取到刚才插入数据库中的id
        -->
        <insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">
            insert into t_user values(#{id},#{username},#{password},#{salt})
        </insert>
        
        <!-- 通过名称查询姓名和密码 -->
        <select id="findByUserName" parameterType="String" resultType="User">
            select id,username,password,salt from t_user
            where username = #{username}
        </select>
        
        <resultMap id="userMap" type="User">
            <id column="uid" property="id"/>
            <result column="username" property="username"/>
            <!--角色信息-->
            <collection property="roles" javaType="list" ofType="Role">
                <id column="id" property="id"/>
                <result column="rname" property="name"/>
            </collection>
        </resultMap>
        <!-- 通过用户名称查询角色信息数据集合,返回用户对象 -->
        <!--这里是三张表进行联合查询 由于表之间是多对多的  所以中间有一张表进行连接  -->
        <select id="findRolesByUserName" parameterType="String" resultMap="userMap">
          SELECT u.id uid,u.username,r.id,r.NAME rname
          FROM t_user u
          LEFT JOIN t_user_role ur
          ON u.id=ur.userid
          LEFT JOIN t_role r
          ON ur.roleid=r.id
          WHERE u.username=#{username}
        </select>
        
        <!-- 通过角色获取权限集合 -->
        <!--三张表联合查询  -->
        <select id="findPermsByRoleId" parameterType="String" resultType="Perms">
          SELECT p.id,p.NAME,p.url,r.NAME
          FROM t_role r
          LEFT JOIN t_role_perms rp
          ON r.id=rp.roleid
          LEFT JOIN t_perms p ON rp.permsid=p.id
          WHERE r.id=#{id}
        </select>
    </mapper>

    认证、授权

    controller.java

    package com.demo.controller;
    
    import javax.servlet.http.HttpSession;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import com.demo.entity.User;
    import com.demo.service.UserService;
    
    @Controller
    @RequestMapping("user")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        /**
         * 用户注册
         */
        @RequestMapping("register")
        public String register(User user) {
            try {
                userService.register(user);
                return "redirect:/login.jsp";
            } catch (Exception e) {
                e.printStackTrace();
                return "redirect:/register.jsp";
            }
        }
    
        /**
         * 退出登录
         */
        @RequestMapping("logout")
        public String logout() {
            Subject subject = SecurityUtils.getSubject();
            subject.logout();// 退出用户
            return "redirect:/login.jsp";
        }
    
        /**
         * 用来处理身份认证
         * 
         * @param username
         * @param password
         * @return
         */
        @RequestMapping("login")
        public String login(String username, String password, String code, HttpSession session) {
            try {
                // 获取主体对象
                Subject subject = SecurityUtils.getSubject();
                // 认证token   这里调用这个login方法的时候 就会执行   realm中的认证方法
                subject.login(new UsernamePasswordToken(username, password));
                return "redirect:/index.jsp";   //这里认证器通过以后  就会进入主页面  这时候分配权限
                //下述报错说明其他错误 重新登陆
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                System.out.println("用户名错误!");
            } catch (IncorrectCredentialsException e) {
                e.printStackTrace();
                System.out.println("密码错误!");
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(e.getMessage());
            }
            return "redirect:/login.jsp";
        }
    }

    shiro配置,shiro.config。过滤器配置资源、安全管理器、获取自定义域realm

    package com.demo.shiro.config;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.cache.ehcache.EhCacheManager;
    import org.apache.shiro.realm.Realm;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import com.demo.shiro.realm.CustomerRealm;
    
    //用来整合shiro框架相关配置类
    //使用spring注解自动注入的功能,调用getXX,注入setXX
    @Configuration
    public class ShiroConfig {
        // shiroFilter 负责拦截所有请求
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            // 给filter设置安全管理器
            shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
            // 配置系统受限资源
            // 配置系统公共资源
            Map<String, String> map = new HashMap<String, String>();
            map.put("/user/login", "anon");// anon 设置为公共资源 放行资源放在下面
            map.put("/user/register", "anon");// anon 设置为公共资源 放行资源放在下面
            map.put("/register.jsp", "anon");// anon 设置为公共资源 放行资源放在下面
            //   /**  受限资源    不受限的资源放在上面
            map.put("/**", "authc");// authc 请求这个资源需要认证和授权 /**拦截所有资源
    
            // 如果没有认证成功就会重定向默认认证界面路径
            shiroFilterFactoryBean.setLoginUrl("/login.jsp");
            
            shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
            return shiroFilterFactoryBean;
        }
    
        // 2.创建安全管理器
        @Bean
        public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm) {
            //安全管理器
            DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
            // 给安全管理器设置realm
            defaultWebSecurityManager.setRealm(realm);
            return defaultWebSecurityManager;
        }
    
        // 3.创建自定义realm
        @Bean
        public Realm getRealm() {
            
            CustomerRealm customerRealm = new CustomerRealm();
            
            // 修改凭证校验匹配器
            HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
            // 设置加密算法为md5
            credentialsMatcher.setHashAlgorithmName("MD5");
            // 设置散列次数
            credentialsMatcher.setHashIterations(1024);
            customerRealm.setCredentialsMatcher(credentialsMatcher);
            
            //开启缓存管理
            //缓存默认实现   缓存的目的是为了让权限存在缓存  下次方便取
            customerRealm.setCacheManager(new EhCacheManager());
            customerRealm.setCachingEnabled(true);//开启全局缓存
            customerRealm.setAuthenticationCachingEnabled(true);//认证认证缓存
            customerRealm.setAuthenticationCacheName("authenticationCache");
            customerRealm.setAuthorizationCachingEnabled(true);//开启授权缓存
            customerRealm.setAuthorizationCacheName("authorizationCache");
            return customerRealm;
        }
    }

      创建自定义域CustomerRealm.java,授权器和认证器,在用户登陆的时候会进行认证器验证账号密码,在登陆完成以后会找到用户对应角色,每个角色所拥有的权限,添加到域中,返回授权器。

    package com.demo.shiro.realm;
    //自定义realm   拿到数据库账号密码的地方
    public class CustomerRealm extends AuthorizingRealm {
    
        //授权器   给用户赋给权限
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            //获取身份信息
            String primaryPrincipal = (String) principals.getPrimaryPrincipal();
            System.out.println("调用授权验证: "+primaryPrincipal);
            //根据主身份信息获取角色 和 权限信息
            UserService userService = (UserService) ApplicationContextUtils
                    .getBean("userService");    
            //这里根据用户名  查到该用户具有哪些角色
            User user = userService.findRolesByUserName(primaryPrincipal);
            
            //授权角色信息 角色存在
            if(!CollectionUtils.isEmpty(user.getRoles())){  //这里说明有很多个角色
                //拿到授权器
                SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
                user.getRoles().forEach(role->{   //这里给每个角色赋权限
                    simpleAuthorizationInfo.addRole(role.getName());
                    //权限信息   更具角色的id 查到该角色拥有的所有权限点
                    List<Perms> perms = userService.findPermsByRoleId(role.getId());
                    if(!CollectionUtils.isEmpty(perms)){
                        perms.forEach(perm->{ 
                            //将权限放到变量中  拿到权限对象的权限名字  添加到可访问域中
                            simpleAuthorizationInfo.addStringPermission(perm.getName());
                        });
                    }
                });
                //返回授权器
                return simpleAuthorizationInfo;
            }
            return null;
        }
    
        //认证器 用户密码登陆验证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("==========================");
            //根据身份信息
            String principal = (String) token.getPrincipal();
            //在工厂中获取service对象
            UserService userService = (UserService) ApplicationContextUtils.getBean("userService");
            //根据用户名  查到对应的用户对象
            User user = userService.findByUserName(principal);
            if(!ObjectUtils.isEmpty(user)){  //对象判空
                return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),
                        //这里生成随机字符串  在SaltUtils工具中生成  在myByteSource中运用
                        new MyByteSource(user.getSalt()),
                        this.getName());
            }
            return null;
        }
    }
    ApplicationContextUtils.java
    package com.demo.utils;
    
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ApplicationContextUtils implements ApplicationContextAware {
    
        //对这个变量赋值以后  这个作为spring容器    
        private static ApplicationContext context;
    
       
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.context = applicationContext;
        }
    
        //拿到容器中已经实例化好的名字的类    根据名字获取类
        //根据bean名字获取工厂中指定bean 对象
        public static Object getBean(String beanName){
            return context.getBean(beanName);
        }
    }
    生成随机字符串,也就是常说的加盐的字符串,字符串处理
    MyByteSource.java
    package com.demo.shiro.salt;
    
    import java.io.File;
    import java.io.InputStream;
    import java.io.Serializable;
    import java.util.Arrays;
    
    import org.apache.shiro.codec.Base64;
    import org.apache.shiro.codec.CodecSupport;
    import org.apache.shiro.codec.Hex;
    import org.apache.shiro.util.ByteSource;
    
    //自定义salt实现  实现序列化接口     加密(加盐操作)
    public class MyByteSource implements ByteSource,Serializable {
    
        private  byte[] bytes;
        private String cachedHex;
        private String cachedBase64;
    
        public MyByteSource(){
    
        }
    
        public MyByteSource(byte[] bytes) {
            this.bytes = bytes;
        }
    
        public MyByteSource(char[] chars) {
            this.bytes = CodecSupport.toBytes(chars);
        }
    
        public MyByteSource(String string) {
            this.bytes = CodecSupport.toBytes(string);
        }
    
        public MyByteSource(ByteSource source) {
            this.bytes = source.getBytes();
        }
    
        public MyByteSource(File file) {
            this.bytes = (new MyByteSource.BytesHelper()).getBytes(file);
        }
    
        public MyByteSource(InputStream stream) {
            this.bytes = (new MyByteSource.BytesHelper()).getBytes(stream);
        }
    
        public static boolean isCompatible(Object o) {
            return o instanceof byte[] || o instanceof char[] || o instanceof String || o instanceof ByteSource || o instanceof File || o instanceof InputStream;
        }
    
        public byte[] getBytes() {
            return this.bytes;
        }
    
        public boolean isEmpty() {
            return this.bytes == null || this.bytes.length == 0;
        }
    
        public String toHex() {
            if (this.cachedHex == null) {
                this.cachedHex = Hex.encodeToString(this.getBytes());
            }
    
            return this.cachedHex;
        }
    
        public String toBase64() {
            if (this.cachedBase64 == null) {
                this.cachedBase64 = Base64.encodeToString(this.getBytes());
            }
    
            return this.cachedBase64;
        }
    
        public String toString() {
            return this.toBase64();
        }
    
        public int hashCode() {
            return this.bytes != null && this.bytes.length != 0 ? Arrays.hashCode(this.bytes) : 0;
        }
    
        public boolean equals(Object o) {
            if (o == this) {
                return true;
            } else if (o instanceof ByteSource) {
                ByteSource bs = (ByteSource)o;
                return Arrays.equals(this.getBytes(), bs.getBytes());
            } else {
                return false;
            }
        }
    
        private static final class BytesHelper extends CodecSupport {
            private BytesHelper() {
            }
    
            public byte[] getBytes(File file) {
                return this.toBytes(file);
            }
    
            public byte[] getBytes(InputStream stream) {
                return this.toBytes(stream);
            }
        }
    
    }

    Salt.java,这里可以直接做运行测试,可以生成一个指定8位的随机字符串

    package com.demo.utils;
    
    import java.util.Random;
    
    public class SaltUtils {
        /**
         * 生成salt的静态方法
         * @param n  返回一个指定长度的盐
         * @return
         */
        public static String getSalt(int n){
            char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < n; i++) {
                char aChar = chars[new Random().nextInt(chars.length)];
                sb.append(aChar);
            }
            return sb.toString();
        }
    
        public static void main(String[] args) {
            String salt = getSalt(8);
            System.out.println(salt);
        }
    }

    前端页面

    login.jsp

    <%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    
        <h1>用户登录</h1>
    
    
        <form action="${pageContext.request.contextPath}/user/login" method="post">
            用户名:<input type="text" name="username" > <br/>
            密码  : <input type="text" name="password"> <br>
            <input type="submit" value="登录">
        </form>
    
    </body>
    </html>

    index.jsp,授权器拿到

    <%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
    <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    
        <h1>系统主页V1.0</h1>
    
        <h1><shiro:principal/></h1>
    
        <shiro:authenticated>
            认证之后展示内容 <br>
        </shiro:authenticated>
        <shiro:notAuthenticated>
            没有认证在之后展示内容
        </shiro:notAuthenticated>
    
        <a href="${pageContext.request.contextPath}/user/logout">退出用户</a>
    
        <ul>
            <shiro:hasAnyRoles name="user,admin">
            <li><a href="">用户管理</a>
                <ul>
                    <shiro:hasPermission name="user:add:*">
                    <li><a href="">添加</a></li>
                    </shiro:hasPermission>
                    <shiro:hasPermission name="user:delete:*">
                        <li><a href="">删除</a></li>
                    </shiro:hasPermission>
                    <shiro:hasPermission name="user:update:*">
                        <li><a href="">修改</a></li>
                    </shiro:hasPermission>
                    <shiro:hasPermission name="order:find:*">
                        <li><a href="">查询</a></li>
                    </shiro:hasPermission>
                </ul>
            </li>
            </shiro:hasAnyRoles>
            <shiro:hasRole name="admin">
                <li><a href="">商品管理</a></li>
                <li><a href="">订单管理</a></li>
                <li><a href="">物流管理</a></li>
            </shiro:hasRole>
        </ul>
    
    </body>
    </html>
  • 相关阅读:
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    mysql备份及恢复
    mysql备份及恢复
    mysql备份及恢复
  • 原文地址:https://www.cnblogs.com/HelloM/p/14156989.html
Copyright © 2011-2022 走看看