• Shiro之基本使用


    在这里插入图片描述
    gitee地址:shiro初体验https://gitee.com/qiangning/shiro-learning.git

    1.什么是Shiro

    Apache Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障 - 从命令行应用、移动应用到大型网络及企业应用。

    Shiro为解决下列问题(我喜欢称它们为应用安全的四要素)提供了保护应用的API:
    认证 - 用户身份识别,常被称为用户“登录”;
    授权 - 访问控制;
    密码加密 - 保护或隐藏数据防止被偷窥;
    会话管理 - 每用户相关的时间敏感的状态。
    Shiro还支持一些辅助特性,如Web应用安全、单元测试和多线程,它们的存在强化了上面提到的四个要素

    2.Shiro核心组件



    2.1 Subject(主体):外部应用的交互,记录当前操作用户,Subject是通过SecurityManager安全管理器进行授权的;

    2.2 SecurityManager(核心安全管理器):对全部Subject进行安全管理,他是核心,SecurityManager通过Authenticato进行认证,通过Authorize授权,通过SessionManager进行会话管理;

          SecurityManager是一个接口继承了Authenticato,Authorize,SessionManage这三个接口
    
    • 1

    2.3 Authenticator(认证器):对用户认证,它是一个接口,shiro提供了ModularRealmAuthenticator实现类,通过实现类可以满足基本要求,也可以自定义认证器;

    2.4 Authorizer(授权器):用户通过认证器来判断用户是否有此功能操作权限;

    2.5 Realm(领域) :相当于数据源,SecuityManager进行认证通过Realm来获取用户权限数据;(从数据库取数据)

    2.6 SessionManager(会话管理) :shiro自定义了一套会话管理,他不依赖web的session,此特性可以使它实现单点登录

    2.7 SessionDAO(会话DAO) :是对session会话的操作,比如将session存储到数据库中,可通过jdbc存储到数据库;

    2.8 CacheManager(缓存管理) :用户权限数据存储在缓存,提高性能;

    2.9 Cryptography(密码管理) shiro提供的一套密码加密解密组件,方便开发;

    3.认证

    3.1 Subject : 主体 ::进行认证的都叫主体

    3.2 Principal :身份信息::必须要有唯一性,一个主体能有多个身份,但是必须有一个主身份

    3.3 Credential :凭证信息::只有主体知道的安全信息

    
      org.apache.shiro
      shiro-core
      1.5.3
    
    
    
    
    配置文件为 .ini后缀;单击测试shiro不用操作数据库;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    demo简单例子

    认证代码:

    public class HaoAuthenticator {
      public static void main(String[] args) {
          //1.创建安全管理器对象
          DefaultSecurityManager securityManager = new DefaultSecurityManager();
          //2.安全管理器设置realm
          securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
          //3.SecurityUtils 全局安全工具类设置安全管理器
          SecurityUtils.setSecurityManager(securityManager);
          //4.关键对象 subject 主体
          Subject subject = SecurityUtils.getSubject();
    
          //5.创建令牌
          UsernamePasswordToken token = new UsernamePasswordToken("admin","root");
    
          try{
              System.out.println("认证状态: "+ subject.isAuthenticated());
              subject.login(token);//用户认证
              System.out.println("认证状态: "+ subject.isAuthenticated());
          }catch (UnknownAccountException e){
              e.printStackTrace();
              System.out.println("认证失败: 用户名不存在~");
          }catch (IncorrectCredentialsException e){
              e.printStackTrace();
              System.out.println("认证失败: 密码错误~");
          }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    4.Realm自定义

    SimpleAccountRealm主要认证和授权源码:

    public class SimpleAccountRealm extends AuthorizingRealm {
    //认证
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            UsernamePasswordToken upToken = (UsernamePasswordToken) token;
            SimpleAccount account = getUser(upToken.getUsername());
    
            if (account != null) {
    
                if (account.isLocked()) {
                    throw new LockedAccountException("Account [" + account + "] is locked.");
                }
                if (account.isCredentialsExpired()) {
                    String msg = "The credentials for account [" + account + "] are expired";
                    throw new ExpiredCredentialsException(msg);
                }
    
            }
    
            return account;
        }
        //授权
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            String username = getUsername(principals);
            USERS_LOCK.readLock().lock();
            try {
                return this.users.get(username);
            } finally {
                USERS_LOCK.readLock().unlock();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    自定义Realm:继承 AuthorizingRealm重写认证和授权

    public class CustomerRealm extends AuthorizingRealm {
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            System.out.println("===授权方法=======");
            return null;
        }
    
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            //在token中获取用户名
            String principal = (String) token.getPrincipal();
            
            System.out.println(principal);
            //根据身份信息使用jdbc mybatis查询数据库
            if("admin".equals(principal)){
             //参数1:返回数据库中正确的用户名   //参数2:返回数据库中正确密码  //参数3:提供当前realm的名字 this.getName();
                SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal,"root",this.getName());
                return simpleAuthenticationInfo;
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    测试自定义Realm

    public class HaoCustomerRealmAuthenticator {
        public static void main(String[] args) {
    
            //创建securityManager
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            //设置自定义realm
            defaultSecurityManager.setRealm(new CustomerRealm());
            //将安全工具类设置安全工具类
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            //通过安全工具类获取subject
            Subject subject = SecurityUtils.getSubject();
            //创建token
            UsernamePasswordToken token = new UsernamePasswordToken("admin", "root");
            try {
                subject.login(token);
                System.out.println(subject.isAuthenticated());
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                System.out.println("用户名错误");
            } catch (IncorrectCredentialsException e) {
                e.printStackTrace();
                System.out.println("密码错误");
            }
           //认证用户进行授权
            if(subject.isAuthenticated()){
                //1.基于角色权限控制
                System.out.println(subject.hasRole("root"));
           }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    使用加密来验证:md5+Salt(”盐“)代码:

    public class HaoShiroMD5 {
        public static void main(String[] args) {
    
            //使用MD5加密
            Md5Hash md5Hash = new Md5Hash("admin");
            System.out.println(md5Hash.toHex());
            
            //使用MD5 + Salt处理
            Md5Hash md5Hash1 = new Md5Hash("admin", "X0*7ps");
            System.out.println(md5Hash1.toHex());
            
            //使用MD5 + Salt + Hash散列
            Md5Hash md5Hash2 = new Md5Hash("admin", "X0*7ps", 1024);
            System.out.println(md5Hash2.toHex());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    使用自定义Realm+MD5+Salt代码

    public class CustomerMd5Realm extends AuthorizingRealm {
    
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            String primaryPrincipal = (String) principals.getPrimaryPrincipal();
            System.out.println("身份信息: "+primaryPrincipal);
    
            //根据身份信息 用户名 获取当前用户的角色信息
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
    
            return simpleAuthorizationInfo;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            //获取身份信息
            String principal = (String) token.getPrincipal();
    
            //根据用户名查询数据库
            if ("admin".equals(principal)) {
                //参数1: 数据库用户名  参数2:数据库md5+salt之后的密码  参数3:注册时的随机盐  参数4:realm的名字
                return new SimpleAuthenticationInfo(principal,
                        "e4f9bf3e0c58f045e62c23c533fcf633",
                        ByteSource.Util.bytes("X0*7ps"),
                        this.getName());
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    测试:

    public class HaoCustomerMd5RealmAuthenicator {
    
        public static void main(String[] args) {
    
            //创建安全管理器
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            //注入realm
            CustomerMd5Realm realm = new CustomerMd5Realm();
            //设置realm使用hash凭证匹配器
            HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
            //使用算法
            credentialsMatcher.setHashAlgorithmName("md5");
            //散列次数
            credentialsMatcher.setHashIterations(1024);
            realm.setCredentialsMatcher(credentialsMatcher);
            defaultSecurityManager.setRealm(realm);
            //将安全管理器注入安全工具
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            //通过安全工具类获取subject
            Subject subject = SecurityUtils.getSubject();
            //认证
            UsernamePasswordToken token = new UsernamePasswordToken("admin", "root");
    
            try {
                subject.login(token);
                System.out.println("登录成功");
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                System.out.println("用户名错误");
            }catch (IncorrectCredentialsException e){
                e.printStackTrace();
                System.out.println("密码错误");
            }
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    4.授权

    访问控制,就是能访问那些东西网页资源,
    授权可简 单理解为who对what(which)进行How操作:

    4.1 WHO

    Who,即主体(Subject),主体需要访问系统中的资源。

    4.2 WHAT

    What,即资源(Resource),如系统菜单、页面、按钮、类方法、
    系统商品信息等。资源包括_资源类型和资源实例_,比如商品信息

    4.3 HOW

    How,权限/许可(Permission),规定了主体对资源的操作许可,

    授权方式
    基于角色访问

    if(subject.hasRore('admin')){
    //操作什么资源
    }
    
    • 1
    • 2
    • 3

    基于资源访问

    if(subject.isPermission("user:update:01")){ //资源实例
    //对01用户进行修改
    }
    if(subject.isPermission("user:update:*")){  //资源类型
    //对01用户进行修改
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    权限字符串: *资源标识符:操作:资源实例标识符;
    eg:
    用户创建权钱:user:create,或user:create:

    用户修改实例:user:update:001
    用户实例所有权限:user:*:001

    shiro授权实现方式:
    编程式:

    Subject subject = SecurityUtils.getSubject();
    if(subject.hasRole(“admin”)) {
    	//有权限
    } else {
    	//无权限
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注解式:

    @RequiresRoles("admin")
    public void hello() {
    	//有权限
    }
    
    • 1
    • 2
    • 3
    • 4

    标签式:

    JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:
    
    
    
    注意: Thymeleaf 中使用shiro需要额外集成!
    
    • 1
    • 2
    • 3
    • 4
    • 5

    开发授权:
    先认证再授权;

    package com.baizhi.realm;
    
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.SimpleAuthenticationInfo;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.util.ByteSource;
    
    /**
     * 使用自定义realm 加入md5 + salt +hash
     */
    public class CustomerMd5Realm extends AuthorizingRealm {
    
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            String primaryPrincipal = (String) principals.getPrimaryPrincipal();
            System.out.println("身份信息: "+primaryPrincipal);
    
            //根据身份信息 用户名 获取当前用户的角色信息,以及权限信息  xiaochen  admin user
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
    
            //将数据库中查询角色信息赋值给权限对象
            simpleAuthorizationInfo.addRole("admin");
            simpleAuthorizationInfo.addRole("user");
    
            //将数据库中查询权限信息赋值个权限对象
            simpleAuthorizationInfo.addStringPermission("user:*:01");
            simpleAuthorizationInfo.addStringPermission("product:create");
    
    
            return simpleAuthorizationInfo;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            //获取身份信息
            String principal = (String) token.getPrincipal();
    
            //根据用户名查询数据库
            if ("Hao".equals(principal)) {
                //参数1: 数据库用户名  参数2:数据库md5+salt之后的密码  参数3:注册时的随机盐  参数4:realm的名字
                return new SimpleAuthenticationInfo(principal,
                        "e4f9bf3e0c58f045e62c23c533fcf633",
                        ByteSource.Util.bytes("X0*7ps"),
                        this.getName());
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    测试

    public class HaoCustomerMd5RealmAuthenicator {
    
        public static void main(String[] args) {
    
            //创建安全管理器
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            //注入realm
            CustomerMd5Realm realm = new CustomerMd5Realm();
            //设置realm使用hash凭证匹配器
    
            HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
            //使用算法
            credentialsMatcher.setHashAlgorithmName("md5");
            //散列次数
            credentialsMatcher.setHashIterations(1024);
            realm.setCredentialsMatcher(credentialsMatcher);
    
            defaultSecurityManager.setRealm(realm);
            //将安全管理器注入安全工具
            SecurityUtils.setSecurityManager(defaultSecurityManager);
    
            //通过安全工具类获取subject
            Subject subject = SecurityUtils.getSubject();
    
            //认证
            UsernamePasswordToken token = new UsernamePasswordToken("hao", "1111");
    
            try {
                subject.login(token);
                System.out.println("登录成功");
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                System.out.println("用户名错误");
            }catch (IncorrectCredentialsException e){
                e.printStackTrace();
                System.out.println("密码错误");
            }
    
    
            //授权
            if(subject.isAuthenticated()){
    
                //基于角色权限控制
                System.out.println(subject.hasRole("super"));
    
                //基于多角色权限控制
                System.out.println(subject.hasAllRoles(Arrays.asList("admin", "super")));
    
                //是否具有其中一个角色
                boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "super", "user"));
                for (boolean aBoolean : booleans) {
                    System.out.println(aBoolean);
                }
                System.out.println("==============================================");
    
                //基于权限字符串的访问控制  资源标识符:操作:资源类型
                System.out.println("权限:"+subject.isPermitted("user:update:01"));
                System.out.println("权限:"+subject.isPermitted("product:create:02"));
    
                //分别具有那些权限
                boolean[] permitted = subject.isPermitted("user:*:01", "order:*:10");
                for (boolean b : permitted) {
                    System.out.println(b);
                }
    
                //同时具有哪些权限
                boolean permittedAll = subject.isPermittedAll("user:*:01", "product:create:01");
                System.out.println(permittedAll);
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    5.整合springboot

    5.1引入依赖

    
      org.apache.shiro
      shiro-spring-boot-starter
      1.5.3
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.1.1创建配置类

    常见过滤器

    配置缩写

    对应的过滤器

    功能

    anon

    AnonymousFilter

    指定url可以匿名访问

    authc

    FormAuthenticationFilter

    指定url需要form表单登录,默认会从请求中获取username、password,rememberMe等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。

    authcBasic

    BasicHttpAuthenticationFilter

    指定url需要basic登录

    logout

    LogoutFilter

    登出过滤器,配置指定url就可以实现退出功能,非常方便

    noSessionCreation

    NoSessionCreationFilter

    禁止创建会话

    perms

    PermissionsAuthorizationFilter

    需要指定权限才能访问

    port

    PortFilter

    需要指定端口才能访问

    rest

    HttpMethodPermissionFilter

    将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释

    roles

    RolesAuthorizationFilter

    需要指定角色才能访问

    ssl

    SslFilter

    需要https请求才能访问

    user

    UserFilter

    需要已登录或“记住我”的用户才能访问

    ==================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================

    5.2 目录:

    在这里插入图片描述

    登录,注册,加盐,数据库,认证:

    ShiroConfig

    package com.hao.shiro.config;
    
    import com.hao.shiro.shiro.realms.CustomerRealm;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    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 java.util.HashMap;
    import java.util.Map;
    
    /*
     *@hao
     *
     *
     *
     */
    @Configuration
    public class ShiroConfig {
    
    
        //创建shiro的filter//负责拦截所有请求
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
    
    
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            //注入安全管理器
            shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
            //配置系统授限资源
    
            //配置系统公共资源
            Map map=new HashMap<>();
            map.put("/user/login.jsp","anon");
            map.put("/user/register.jsp","anon");
            map.put("/index.jsp","authc");//请求这个资源需要认证和授权
            shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
            //默认认证界面
            shiroFilterFactoryBean.setLoginUrl("/login.jsp");
    
            return shiroFilterFactoryBean;
        }
    
        //创建安全管理器
        @Bean
        public DefaultWebSecurityManager getdefaultWebSecurityManager (Realm realm){
            DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
            //给安全管理器设置
            defaultWebSecurityManager.setRealm(realm);
            return defaultWebSecurityManager;
        }
    
        //创建自定义realm
        @Bean
        public Realm getRealm(){
    
            CustomerRealm customerRealm = new CustomerRealm();
            //设置hashed凭证匹配器
            HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
            //设置md5加密
            credentialsMatcher.setHashAlgorithmName("md5");
            //设置散列次数
            credentialsMatcher.setHashIterations(1024);
            customerRealm.setCredentialsMatcher(credentialsMatcher);
            return customerRealm;
    
    
        }
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    UserController

    package com.hao.shiro.controller;
    
    
    import com.hao.shiro.entity.User;
    import com.hao.shiro.service.UserService;
    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;
    
    
    /*
     *@hao
     *
     *
     *
     */
    @Controller
    @RequestMapping("user")
    public class UserController {
    
    
    
        @RequestMapping("/logout")
        public String logout(){
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
            System.out.println("退出登录");
            return "redirect:/login.jsp";
    
        }
    
    
        @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("login")
        public String login(String username,String password){
    
            //获取主体对象
            Subject subject= SecurityUtils.getSubject();
    
            try {
                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("密码错误");
            }
            return "redirect:/login.jsp";
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    UserDAO

    package com.hao.shiro.dao;
    
    import com.hao.shiro.entity.User;
    import org.apache.ibatis.annotations.Mapper;
    
    /*
     *@hao
     *
     *
     *
     */
    @Mapper
    public interface UserDAO {
        void save(User user);
        User findByUserName(String username);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    User

    package com.hao.shiro.entity;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.Accessors;
    
    /*
     *@hao
     *
     *
     *
     */
    @Data
    @Accessors(chain = true)
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private String id;
        private String username;
        private String password;
        private String salt;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    UserService

    package com.hao.shiro.service;
    
    import com.hao.shiro.entity.User;
    
    public interface UserService {
        void register(User user);
        User findByUserName(String username);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    UserServiceImpl

    package com.hao.shiro.service;
    
    import com.hao.shiro.dao.UserDAO;
    import com.hao.shiro.entity.User;
    import com.hao.shiro.utils.SaltUtils;
    import org.apache.shiro.crypto.hash.Md5Hash;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    /*
     *@hao
     *
     *
     *
     */
    @Service("userService")
    @Transactional
    public class UserServiceImpl implements UserService {
        @Autowired
        private UserDAO userDAO;
    
    
        @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);
    
    
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    CustomerRealm

    package com.hao.shiro.shiro.realms;
    
    import com.hao.shiro.entity.User;
    import com.hao.shiro.service.UserService;
    import com.hao.shiro.utils.ApplicationContextUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.SimpleAuthenticationInfo;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.util.ByteSource;
    import org.springframework.util.ObjectUtils;
    
    /*
     *@hao
     *
     *
     *
     */
    public class CustomerRealm extends AuthorizingRealm {
        //处理授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            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(),
                        ByteSource.Util.bytes(user.getSalt()),this.getName());
            }
    
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    ApplicationContextUtils

    package com.hao.shiro.utils;
    
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    /*
     *@hao
     *
     *
     *
     */
    @Component
    public class ApplicationContextUtils implements ApplicationContextAware {
        private static ApplicationContext context;
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.context=applicationContext;
        }
        public static Object getBean(String beanName){
    
            return context.getBean(beanName);
        }
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    SaltUtils

    package com.hao.shiro.utils;
    
    import java.util.Random;
    
    /*
     *@hao
     *
     *
     *
     */
    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    applicattin

    server.port=8080
    
    server.servlet.context-path=/shiro
    spring.application.name=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?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
    spring.datasource.username=root
    spring.datasource.password=root
    
    
    
    mybatis.type-aliases-package=com.hao.shiro.entity
    mybatis.mapper-locations=classpath:mapper/*.xml
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Mapper->UserDaoMapper.xml

    
    
    
    
        
      insert into t_user values(#{id},#{username},#{password},#{salt})
     
    
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    webapp–>
    index.jsp

    <%@page contentType="text/html;  utf-8"  pageEncoding="utf-8" isELIgnored="false" %>
    
    
        
        
        
        主页
    
    
    

    系统主页

    退出登录
    1. 用户页面
    2. 食品页面
    3. 订单页面
    4. 物流页面
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    login.jsp

    <%@page contentType="text/html;  utf-8"  pageEncoding="utf-8" isELIgnored="false" %>
    
    
        
        
        
        用户登录
    
    
    

    用户登录

    用户名:
    密 码: 立即注册
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    register.jsp

    <%@page contentType="text/html;  utf-8"  pageEncoding="utf-8" isELIgnored="false" %>
    
    
        
        
        
        用户登录
    
    
    

    用户注册

    用户名:
    密 码:
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    授权整合以及redis缓存整合

    在这里插入图片描述

    开启自带缓存

     //开启自带的缓存管理
            customerRealm.setCacheManager(new EhCacheManager());
            customerRealm.setCachingEnabled(true);//开启全局缓存
            customerRealm.setAuthenticationCachingEnabled(true);//认证认证缓存
            customerRealm.setAuthenticationCacheName("authenticationCache");
            customerRealm.setAuthorizationCachingEnabled(true);//开启授权缓存
            customerRealm.setAuthorizationCacheName("authorizationCache");
            return customerRealm;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    pom主要导入依赖

            
                org.apache.shiro
                shiro-spring-boot-starter
                1.5.3
            
    
    
            
                org.apache.tomcat.embed
                tomcat-embed-jasper
            
            
                javax.servlet
                jstl
                1.2
            
    
            
            
                org.mybatis.spring.boot
                mybatis-spring-boot-starter
                2.1.2
            
    
            
            
                mysql
                mysql-connector-java
                5.1.38
            
    
    
            
            
                com.alibaba
                druid
                1.1.19
            
            
            
                org.apache.shiro
                shiro-ehcache
                1.5.3
            
    
            
            
                org.springframework.boot
                spring-boot-starter-data-redis
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    配置文件

    server.port=8080
    
    server.servlet.context-path=/shiro
    spring.application.name=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?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
    spring.datasource.username=root
    spring.datasource.password=root
    
    
    
    mybatis.type-aliases-package=com.hao.shiro.entity
    mybatis.mapper-locations=classpath:mapper/*.xml
    
    spring.redis.port=6379
    spring.redis.host=localhost
    spring.redis.database=0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    sql

    /*
    SQLyog Professional v12.09 (64 bit)
    MySQL - 5.7.34-log : Database - shiro
    *********************************************************************
    */
    
    
    /*!40101 SET NAMES utf8 */;
    
    /*!40101 SET SQL_MODE=''*/;
    
    /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
    /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
    /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
    /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
    CREATE DATABASE /*!32312 IF NOT EXISTS*/`shiro` /*!40100 DEFAULT CHARACTER SET utf8 */;
    
    USE `shiro`;
    
    /*Table structure for table `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;
    
    /*Data for the table `t_perms` */
    
    insert  into `t_perms`(`id`,`name`,`url`) values (1,'user:*:*',NULL),(2,'product:*:01',NULL),(3,'order:*:*',NULL);
    
    /*Table structure for table `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;
    
    /*Data for the table `t_role` */
    
    insert  into `t_role`(`id`,`name`) values (1,'admin'),(2,'user'),(3,'product');
    
    /*Table structure for table `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;
    
    /*Data for the table `t_role_perms` */
    
    insert  into `t_role_perms`(`id`,`roleid`,`permsid`) values (1,1,1),(2,1,2),(3,2,1),(4,3,2),(5,1,3);
    
    /*Table structure for table `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=3 DEFAULT CHARSET=utf8;
    
    /*Data for the table `t_user` */
    
    insert  into `t_user`(`id`,`username`,`password`,`salt`) values (1,'hao','567f86681241739ba8cf3d26e52eaafc','XK&7UIS^'),(2,'qiang','d750daee137e0666193a1720732fe97d','UVcob7pR');
    
    /*Table structure for table `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;
    
    /*Data for the table `t_user_role` */
    
    insert  into `t_user_role`(`id`,`userid`,`roleid`) values (1,1,1),(2,2,2),(3,2,3);
    
    /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
    /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
    /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
    /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
  • 相关阅读:
    【Mybatis小白从0到90%精讲】04:Mybatis工具类
    TypeScript 面向对象编程
    Es修改索引别名
    MCE | 癌相关基因 ALK 参与胖瘦调节
    第四章 ObjectScript 宏预处理器指令
    城市易涝点怎么安装万宾科技内涝积水监测仪?
    Saas型网站域名如何接入腾讯云的web应用防火墙?
    ASO优化之关于健身应用的优化策略
    c++-string
    AWS无服务器 应用程序开发—第十四章 实战1
  • 原文地址:https://blog.csdn.net/m0_67391870/article/details/126496238