• Shiro入门


    Shiro的使用

    今天学习了Shiro框架,感觉不是很懂,有点懵,写篇随笔记录一下

    1. Shiro三个核心组件

    1.1 Subject
      Subject:即“当前操作用发户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。

    1.2 SecurityManager
      SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。

    1.3 Realm
      Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
      从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
      Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

    2. Shiro相关类介绍

    (1)Authentication 认证 ---- 用户登录
    (2)Authorization 授权 --- 用户具有哪些权限
    (3)Cryptography 安全数据加密
    (4)Session Management 会话管理
    (5)Web Integration web系统集成
    (6)Interations 集成其它应用,spring、缓存框架

    3. Shiro 特点

    (1)易于理解的 Java Security API;
    (2)简单的身份认证(登录),支持多种数据源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
    (3)对角色的简单的签权(访问控制),支持细粒度的签权;
    (4)支持一级缓存,以提升应用程序的性能;
    (5)内置的基于 POJO 企业会话管理,适用于 Web 以及非 Web 的环境;
    (6)异构客户端会话访问;
    (7)非常简单的加密 API;
    (8)不跟任何的框架或者容器捆绑,可以独立运行

    一. 新建SpringBoot项目,导入相关依赖,

    <!--
                Subject 用户
                SecurityManager 管理所有用户
                Realm 连接数据
    -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
    <dependency>
        <groupId>com.github.theborakompanioni</groupId>
        <artifactId>thymeleaf-extras-shiro</artifactId>
        <version>2.0.0</version>
    </dependency>
    
    

    二. 创建数据库、实体类以及mapper配置文件(为了方便直接使用上一篇整合Myabtis的数据库和文件)

    1.创建数据库表

    DROP DATABASE IF EXISTS mybatis;
    CREATE DATABASE mybatis;
    
    DROP TABLE  IF EXISTS USER;
    CREATE TABLE USER(
    	id INT PRIMARY KEY AUTO_INCREMENT,
    	username VARCHAR(32) NOT NULL COMMENT '姓名',
    	PASSWORD VARCHAR(32) NOT NULL COMMENT '密码',
        perms 	VARCHAR(32) NOT NULL COMMENT '权限参数'
    )ENGINE=INNODB AUTO_INCREMENT=1 CHARSET=utf8;
    
    INSERT INTO USER(username,PASSWORD,perms) VALUES("niubi","123456","user-add");
    INSERT INTO USER(username,PASSWORD,perms) VALUES("wocao","123456","user-update");
    INSERT INTO USER(username,PASSWORD) VALUES("Java","123456");
    INSERT INTO USER(username,PASSWORD) VALUES("python","123456");
    INSERT INTO USER(username,PASSWORD) VALUES("C","123456");
    

    2.创建实体类

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private Integer id;
        private String username;
        private String password;
        private String perms;
    }
    

    3.创建UserMapper接口

    
    @Mapper//表示本类是一个Mybatis的mapper
    @Repository//不加也可以,但是Controller会报错,但是不影响正常运行
    public interface UserMapper {
        //根据用户名查询用户
        User findUserByUserName(String username);
    }
    

    4.编写UserMapper.xml配置文件

    <?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.gaoteng.mapper.UserMapper">
    
        <select id="findUserByUserName" resultType="User">
            select * from user where username = #{username}
        </select>
    </mapper>
    

    5.编写application.properties配置文件

    
    # 配置数据源
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&serverTimezone=UTC&characterEncoding=utf-8
    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    # 开启别名映射
    mybatis.type-aliases-package=com.gaoteng.pojo
    # mapper的路径 就是xml配置文件中的<mappers>标签
    mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
    

    三. 编写前端页面

    首页

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>
     	 <a th:href="@{/user/toLogin}" shiro:guest="">登录</a>
        <a th:href="@{/user/logout}" style="float: right">注销用户</a>
        <div shiro:hasPermission="user:add">
            <a th:href="@{/user/add}">add</a><br>
        </div>
        <div shiro:hasPermission="user:update">
            <a th:href="@{/user/update}">update</a>
        </div>
    </body>
    </html>
    

    add.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>add</h1>
    </body>
    </html>
    

    login.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h2>登录</h2>
        <p th:text="${msg}"></p>
        <hr>
        <form method="post" th:action="@{/login}">
            用户名:<input type="text" name="username"><br>
            密码:<input type="password" name="password"><br>
            <input type="submit" value="提交">
        </form>
    </body>
    </html>
    

    upodate.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>update</h1>
    </body>
    </html>
    

    四.新建config包,创建ShiroConfig配置文件和UserRealm类

    package com.gaoteng.config;
    
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    @Configuration
    public class ShiroConfig {
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
            ShiroFilterFactoryBean bean= new ShiroFilterFactoryBean();
            bean.setSecurityManager(securityManager);
            //添加Shiro的内置过滤器
            /*
            *   anon:无需认证就能访问
            *   authc:必须认证了才能访问
            *   user:必须拥有 记住我 功能才能访问
            *   perms:拥有对某个资源的权限才能访问
            *   roles:拥有某个角色权限才能访问
            *	logout:注销
            * */
            //拦截
            Map<String,String> filterMap = new LinkedHashMap<>();
            filterMap.put("/user/add","authc");
            filterMap.put("/user/update","authc");
            //注销  
            filterMap.put("/user/logout","logout");
            //授权  正常情况下,没有授权就会跳转到未授权页面
            filterMap.put("/user/add","perms[user:add]");
            filterMap.put("/user/update","perms[user:update]");
            bean.setFilterChainDefinitionMap(filterMap);
            //设置登录的请求
            bean.setLoginUrl("/user/toLogin");
            //设置未授权页面
            bean.setUnauthorizedUrl("/noauth");
            return bean;
    
        }
    
        @Bean
        @Qualifier("securityManager")
        public DefaultWebSecurityManager defaultWebSecurityManager(@Autowired UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //关联UserRealm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
    
        @Bean
        public UserRealm userRealm(){
            return new UserRealm();
        }
         @Bean
        public ShiroDialect shiroDialect() {
            return new ShiroDialect();
        }
    }
    
    
    package com.gaoteng.config;
    
    
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    
    
    public class UserRealm extends AuthorizingRealm {
         @Autowired
        UserMapper userMapper;//这里为了方便演示,没有编写Service层
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("授权");
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            //给所有用户增加user:add权限
            //info.addStringPermission("user:add");
    
            //拿到当前登录的用户对象
            Subject subject = SecurityUtils.getSubject();
            User currentUser = (User) subject.getPrincipal();
            //设置当前用户的权限
            info.addStringPermission(currentUser.getPerms());
            return info;
        }
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println("认证");
            //用户名和密码
            UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
            //获取用户名
            String username = userToken.getUsername();
            //根据用户名查询用户是否存在
            User user = userMapper.findUserByUserName(username);
            if(user==null){
                return null;//抛出UnknownAccountException异常
            }
            //密码是由Shiro来处理
            return new SimpleAuthenticationInfo(user,user.getPassword(),"");
        }
    }
    
    

    四. 编写Cotroller

    package com.gaoteng.controller;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    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.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class TestController {
        @RequestMapping({"/","/index","/index.html"})
        public String index(Model model){
            model.addAttribute("msg","niubi");
            return "index";
        }
        @RequestMapping("/user/add")
        public String add(){
            return "add";
        }
        @RequestMapping("/user/update")
        public String update(){
            return "update";
        }
        @RequestMapping("/user/toLogin")
        public String toLogin(){
            return "login";
        }
        @RequestMapping("/login")
        public String login(String username,String password,Model model){
            //获取当前用户
            Subject subject = SecurityUtils.getSubject();
            //封装用户的登录数据
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    
            try {
                //执行登陆方法
                subject.login(token);
                return "redirect:index";
            } catch (UnknownAccountException e) {
                      model.addAttribute("msg","用户名不存在");
                      return "login";
            }catch (IncorrectCredentialsException e){
                    model.addAttribute("msg","密码错误");
                    return "login";
            }
        }
         @RequestMapping("/noauth")
        @ResponseBody
        public String unauthorized(){
            return "未经授权,无法访问";
        }
        //注销 如果注销操作中需要额外的操作时,可以自己编写Controller处理,如果只需要简单的注销功能,
        //只需要在Shiro的内置过滤器中添加类似于filterMap.put("/user/logout","logout");的代码
       /* @RequestMapping("/user/logout")
        public String logout(){
             Subject subject = SecurityUtils.getSubject();
        	subject.logout();
        	return "login";
        }*/
    }
    
    

    因为运行要演示的图片太多,所以这里就不演示了.

    不过我现在只知道怎么使用,并不了解原理.如果想了解原理的话,可以请阅读其它文章.

    本篇随笔借鉴了以下文章或视频:[权限框架之Shiro详解(非原创)](https://www.cnblogs.com/WUXIAOCHANG/p/10886534.html)

    shiro常用标签

    springboot整合shiro -shiro介绍(一)
    【狂神说Java】SpringBoot最新教程IDEA版通俗易懂

  • 相关阅读:
    clip-path
    box-reflect
    循环内click赋值跳转
    github pages 不能识别下划线开头的文件
    Telerik Reporting
    VS2015项目发布失败且没有错误提示
    kendo grid 过滤器
    kendo 月份选择
    kendo grid过滤
    odata连接现有数据库
  • 原文地址:https://www.cnblogs.com/gttttttt/p/13060452.html
Copyright © 2020-2023  润新知