• Springboot:自定义Realm


    1、导入依赖

    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <!-- MyBatis -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.0</version>
            </dependency>
            <!-- mysql驱动 依赖 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.25</version>
                <scope>runtime</scope>
            </dependency>
            <!--Druid-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.10</version>
            </dependency>
            <!--shiro-->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.4.1</version>
            </dependency>
            <!--shiro标签 xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro" -->
            <dependency>
                <groupId>com.github.theborakompanioni</groupId>
                <artifactId>thymeleaf-extras-shiro</artifactId>
                <version>2.0.0</version>
            </dependency>
        </dependencies>

    2、书写配置类

    @Configuration
    public class ShiroConfig {
        @Bean
        public ShiroDialect getShiroDialect() {
            return new ShiroDialect();
        }
    
        @Bean//realm
        public MyRealm getMyRealm(DataSource dataSource) {
            MyRealm myRealm = new MyRealm();
            return myRealm;
        }
    
        @Bean//安全管理器
        public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm) {
            DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
            defaultSecurityManager.setRealm(myRealm);//SecurityManager完成校验需要realm
            return defaultSecurityManager;
        }
    
        @Bean//过滤器
        public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultSecurityManager securityManager) {
            ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
            //过滤器是shiro执行权限的核心,进行认证和授权是需要SecurityManager的
            filter.setSecurityManager(securityManager);
            //设置shiro的拦截规则
            Map<String, String> filterMap = new HashMap<>();
            //user:使用remberme的用户可访问
            //perms:对应权限可访问
            //role:对应的角色才能访问
            filterMap.put("/", "anon");//anon表示不拦截(匿名用户可访问)
            filterMap.put("/login.html", "anon");
            filterMap.put("/regist.html", "anon");
            filterMap.put("/user/login", "anon");
            filterMap.put("/user/regist", "anon");
            filterMap.put("/static/**", "anon");
            filterMap.put("/index.html", "anon");
            filterMap.put("/**", "authc");//authc表示认证用户可访问
            filter.setFilterChainDefinitionMap(filterMap);
            filter.setLoginUrl("/login.html");
            //设置未授权访问的页面
            filter.setUnauthorizedUrl("/login.html");
            return filter;
        }
    }

           配置类中的Realm需要自定义,在使用ini文件作为数据源的时候使用的是lniRealm,使用数据库作为数据源的时候使用的是JdbcRealm,JdbcRealm中的数据库的表名称与表的字段名称都是固定的。在使用自定义Realm之后数据库不是固定不变的,但是dao层需要我们自己书写代码来完成实现,配置类中的Realm也需要我们自己定义。

    3、自定义Realm

    public class MyRealm extends AuthorizingRealm {//实现了接口的类才是一个realm类
        @Autowired
        private UserDao userDao;
        @Autowired
        private RoleDao roleDao;
        @Autowired
        private PermissionDao permissionDao;
    
        public String getName() {
            return "myRealm";
        }
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            //获取当前认证的用户的用户名,跟doGetAuthenticationInfo方法中的new SimpleAuthenticationInfo参数是对应的,获取到的数据与认证的时候封装的数据是对应的
            String username= (String) principalCollection.iterator().next();
            //根据用户名查询当前用户的前台列表,Set集合能够去除重复的数据
            Set<String> roleNames=roleDao.queryRoleNameByUsername(username);
            Set<String> ps=permissionDao.queryPermissionsByUsername(username);
            SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
            info.setRoles(roleNames);
            info.setStringPermissions(ps);
            return info;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //参数authenticationToken就是传递的subject.login(token)中的参数
            UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
            //从token中获取用户名
            String username=token.getUsername();
    //根据用户名查询用户的安全数据(数据库中的用户数据) User user
    = userDao.getUserByUsername(username); if(user==null){ return null; } AuthenticationInfo info=new SimpleAuthenticationInfo(//将密码封装为shiro需要的格式 username,//当前用户用户名,跟上面的doGetAuthorizationInfo方法是对应的 user.getUserPwd(),//从数据库查询出来的安全密码 getName()); return info; } }
    • 创建一个类并继承AuthorizingRealm类
    • 重写doGetAuthorizationInfo获取授权信息和doGetAuthenticationInfo方法来获取认证信息
    • 重写getName方法返回当前realm的一个自定义名称

    4、controller层

    (1)页面跳转所需要的controller

    @Controller
    public class PageController {
        @RequestMapping("/login.html")
        public String login(){
            return "login";
        }
    
        @RequestMapping("/")
        public String login1(){
            return "login";
        }
    
        @RequestMapping("/index.html")
        public String index(){
            return "index";
        }
    }

    (2)用户登录的controller

    @Controller
    @RequestMapping("user")
    public class UserController {
        @Autowired
        private UserService userService;
        @RequestMapping("login")
        public String login(String username,String password){
            try{
                userService.checkLogin(username,password);
                System.out.println("成功");
                System.out.println(username+password);
                return "index";
            }catch (Exception e){
                e.printStackTrace();
                System.out.println("失败");
                System.out.println(username+password);
                return "login";
            }
        }
    }

    5、service层

    @Service
    public class UserService {
        public void checkLogin(String username,String password) throws Exception{
            Subject subject= SecurityUtils.getSubject();
            UsernamePasswordToken token=new UsernamePasswordToken(username,password);
            subject.login(token);
        }
    }

    完成用户的认证

    6、dao层

    用户:

    @Repository
    public interface UserDao {
         User getUserByUsername(String username);//用户名获取用户
    }
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.zhb.dao.UserDao">
        <resultMap id="userMap" type="User">
            <id column="user_id" property="userId"></id>
            <result column="username" property="userName"></result>
            <result column="password" property="userPwd"></result>
            <result column="password_salt" property="pwdSalt"></result>
        </resultMap>
        <select id="getUserByUsername" resultMap="userMap">
            select * from tb_users
            where username=#{username}
        </select>
    </mapper>

    角色:

    @Repository
    public interface RoleDao {
        public Set<String> queryRoleNameByUsername(String username);//用户名获取角色
    }
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.zhb.dao.RoleDao">
        <select id="queryRoleNameByUsername" resultType="String" resultSets="java.util.Set">
            SELECT role_name
            FROM tb_users INNER JOIN tb_urs ON tb_users.user_id = tb_urs.uid
            INNER JOIN tb_roles ON tb_urs.rid = tb_roles.role_id
            WHERE tb_users.username=#{username}
        </select>
    </mapper>

    权限:

    @Repository
    public interface PermissionDao {
        public Set<String> queryPermissionsByUsername(String username);
    }
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.zhb.dao.PermissionDao">
        <select id="queryPermissionsByUsername" resultType="String" resultSets="java.util.Set">
            SELECT tb_permissions.permission_code FROM tb_users
            INNER JOIN tb_urs ON tb_users.user_id = tb_urs.uid
            INNER JOIN tb_roles ON tb_urs.rid = tb_roles.role_id
            INNER JOIN tb_rps ON tb_roles.role_id = tb_rps.rid
            INNER JOIN tb_permissions ON tb_rps.pid = tb_permissions.permission_id
            WHERE tb_users.username=#{username}
        </select>
    </mapper>

    7、bean

    @Data
    public class User {
        private Integer userId;
        private String userName;
        private String userPwd;
        private String pwdSalt;
    }

    8、yml配置文件

    spring:
      datasource:
        druid:
          username: root
          password: root
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://localhost:3306/myshiro?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
          initialSize: 5
          minIdle: 5
          maxActive: 20
          maxWait: 60000
          timeBetweenEvictionRunsMillis: 60000
          minEvictableIdleTimeMillis: 300000
          validationQuery: SELECT 1 FROM DUAL
          testWhileIdle: true
          testOnBorrow: false
          testOnReturn: false
          poolPreparedStatements: true
    # mybatis配置
    mybatis:
      mapper-locations: classpath:mappers/*.xml    # mapper映射文件位置
      type-aliases-package: com.zhb.beans    # 实体类所在的位置
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl   #用于控制台打印sql语句

    配置数据源与mybatis,其中mybatis配置xml文件的位置、实体类位置、以及控制台打印SQL语句

    9、页面

    登录页:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>login</title>
    </head>
    <body>
        <form action="/user/login">
            <input type="text" name="username">
            <input type="password" name="password">
            <input type="submit" value="提交">
        </form>
    </body>
    </html>

    主页:

    <!DOCTYPE html>
    <html lang="en" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
    <h3>index</h3>
    <hr/>
    <shiro:guest>
        欢迎游客访问<a href="login.html">登录</a>
    </shiro:guest>
    <shiro:user>
        用户[
        <shiro:principal/>
        ]登录成功
        当前用户的身份
        <shiro:hasRole name="管理员">管理员</shiro:hasRole>
        <shiro:hasRole name="学生">学生</shiro:hasRole>
        <hr/>
        学生:
        <ul>
            <shiro:hasPermission name="stu_select">
                <li><a href="#">查询</a></li>
            </shiro:hasPermission>
        </ul>
        <hr/>
        教师:
        <ul>
            <shiro:hasPermission name="tea_select">
                <li><a href="#">查询</a></li>
            </shiro:hasPermission>
        </ul>
        <ul>
            <shiro:hasPermission name="tea_delete">
                <li><a href="#">删除</a></li>
            </shiro:hasPermission>
        </ul>
        <ul>
            <shiro:hasPermission name="tea_update">
                <li><a href="#">修改</a></li>
            </shiro:hasPermission>
        </ul>
        管理员:
        <ul>
            <shiro:hasPermission name="man_select">
                <li><a href="#">查询</a></li>
            </shiro:hasPermission>
        </ul>
        <ul>
            <shiro:hasPermission name="man_delete">
                <li><a href="#">删除</a></li>
            </shiro:hasPermission>
        </ul>
        <ul>
            <shiro:hasPermission name="man_update">
                <li><a href="#">修改</a></li>
            </shiro:hasPermission>
        </ul>
        <ul>
            <shiro:hasPermission name="man_add">
                <li><a href="#">添加</a></li>
            </shiro:hasPermission>
        </ul>
    </shiro:user>
    </body>
    </html>

    11、数据库设计(五张表)

    (1)用户表

    (2)用户角色表

    (3)角色表

    (4)角色权限表

    (5)权限

       这些表都是自定义的,不是shiro默认的表,字段也不局限于shiro默认的表的字段,因为dao层是我们自己实现的。

    11、测试

    (1)管理员

     (2)学生

     (3)教师

    每个人都会有一段异常艰难的时光 。 生活的压力 , 工作的失意 , 学业的压力。 爱的惶惶不可终日。 挺过来的 ,人生就会豁然开朗。 挺不过来的 ,时间也会教你 ,怎么与它们握手言和 ,所以不必害怕的。 ——杨绛
  • 相关阅读:
    在Intellij idea 2017中运行tomcat 8.5
    Servlet技术之服务器的安装和配置
    Servlet&&Jsp 概述
    linux 下 tomcat 安装
    执行数据库的更新操作
    JDBC
    Mysql 命令
    hdoj2036 改革春风吹满地——叉积
    常规设置
    pytorch本地安装
  • 原文地址:https://www.cnblogs.com/zhai1997/p/13719489.html
Copyright © 2020-2023  润新知