Shiro框架学习笔记、整合Springboot、redis缓存

news2025/2/2 12:52:55

本笔记基于B站UP主不良人编程

目录

1.权限的管理

1.1什么是权限管理

1.2什么是身份认证

1.3什么是授权

2.什么是Shiro

3.Shiro的核心架构

 3.1 S核心内容

4.shiro中的认证4.1认证

4.2shiro中认证的关键对象

4.3认证流程

 4.4认证程序开发流程

 4.4认证程序源码 

4.5自定义Realm

4.6使用DM5和Salt

5.shiro中的授权

5.1授权

5.2关键对象

5.3授权流程

 5.4授权方式

5.5权限字符串

5.6 shiro中授权编程实现方式

 5.7开发授权

6基于SpringBoot整合

6.1引入shiro依赖

6.2配置shiro环境

6.3MD5、Salt的认证实现 

6.4shiro中授权编程实现方式-代码实现

6.5.shiro整合springboot之授权数据的数据库获取

 6.8使用CacheManager1.Cache作用

 2.使用shiro中默认EhCache实现缓存

6.9Shiro整合springboot缓存之Redis


1.权限的管理


1.1什么是权限管理


  基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略 控制用户可以访问而且只能访问自己被授权的资源。
  权限管理包括用户身份认证授权两部分,简称认证授权。对于需要访问控制的资源用户首先经过身份认证,认证通过后用户具有该资源的访问权限方可访问。

1.2什么是身份认证


  身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。对于采用指纹等系统,则出示
指纹;对于硬件Ky等刷卡系统,则需要刷卡。

1.3什么是授权


  授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没权限是无法访问的

2.什么是Shiro

Apache Shiro是一个功能强大且易于使用的 Java 安全框架,它执行身份验证、授权、加密和会话管理。使用 Shiro 易于理解的 APl,您可以快速而轻松地保护任何应用程序——从最小的移动应用程序到最大的 Web 和企业应用程序

3.Shiro的核心架构

 3.1 S核心内容


Subject(用户):当前的操作用户 获取当前用户Subject currentUser = SecurityUtils.getSubject()
SecurityManager(安全管理器):Shiro的核心,负责与其他组件进行交互,实现 subject 委托的各种功能
Realms(数据源) :Realm会查找相关数据源,充当与安全管理间的桥梁,经过Realm找到数据源进行认证,授权等操作
Authenticator(认证器): 用于认证,从 Realm 数据源取得数据之后进行执行认证流程处理。
Authorizer(授权器):用户访问控制授权,决定用户是否拥有执行指定操作的权限。
SessionManager (会话管理器):支持会话管理
CacheManager (缓存管理器):用于缓存认证授权信息
Cryptography(加密组件):提供了加密解密的工具包

4.shiro中的认证
4.1认证


身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。


4.2shiro中认证的关键对象

Subject:主体
访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体;
Principal:身份信息
是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(PrimaryPrincipal)
“credential:凭证信息!
是只有主体自己知道的安全信息,如密码、证书等。

4.3认证流程

 4.4认证程序开发流程

注意点:shiro配置文件
.ini结尾文件   .txt   .ini复杂数据格式

shiro配置文件

[users]
hzw=123
zhangsan=123456
ryw=1233

shiro所需依赖

    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.3.2</version>
    </dependency>
package com.hzw.shiro;
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.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;

public class Authenticator {
    public static void main(String[] args) {
        //1.创建安全管理器对象 ctrl +h 看结构图
        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("hzw", "123");
        try {
            System.out.println("认证状态"+subject.isAuthenticated());
            //登录
            subject.login(token);
            System.out.println("认证状态"+subject.isAuthenticated());
            //退出登录
            subject.logout();
            System.out.println("认证状态"+subject.isAuthenticated());
        } catch ( UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名不存在");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误");
        }
    }
}

测试结果

 4.4认证程序源码 

认证:
1.最终执行用户名比较SimpleAccountRealm
doGetAuthenticationInfo在这个方法中完成用户名校验
2.最终密码校验是在AuthenticatingRealm中
assertCredentialsMatch

总结

AuthenticatingRealm   认证realm   doGetAuthenticationInfo
AuthorizingRealm   授权realm   doGetAuthorizationInfo

4.5自定义Realm

实现代码 

自定义Realm

package com.hzw.shiro.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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

//自定义realm实现将认证/授权数据的来源转为数据库的实现
public class CustomerRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
       //token获取用户名
        String principal = (String) token.getPrincipal();
        System.out.println(principal);
        //判断
        if ("hzw".equals(principal)){
            //
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, "123", this.getName());
            return simpleAuthenticationInfo;
        }
        return null;
    }
}

测试代码

package com.hzw.shiro.realm;

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.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;

public class RealmTest {
    public static void main(String[] args) {
        //1.创建安全管理器对象 ctrl +h 看结构图
        DefaultSecurityManager securityManager=new  DefaultSecurityManager();
        //2.安全管理系设置 Realm
       // securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
        //2.自定义Realm
        securityManager.setRealm(new CustomerRealm());
        //3.SecurityUtils 全局安全工具类设置安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        //4.Subject:主体
        Subject subject = SecurityUtils.getSubject();
        //5创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("hzw", "123");
        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("密码错误");
        }
    }
}

4.6使用DM5和Salt


实际应用是将盐和散列后的值存在数据库中,自动realm从数据库取出盐和加密后的值由shr©完成密码校验。

依赖

  <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.3.2</version>
    </dependency>

MD5、salt、hash密文

package com.hzw.shiro;

import org.apache.shiro.crypto.hash.Md5Hash;

public class Md5Test {
    public static void main(String[] args) {
        //使用md5
        Md5Hash md5Hash  =new Md5Hash("123");
        System.out.println(md5Hash.toHex());
//使用MD5+sa1t处理
        Md5Hash md5Hash1 = new Md5Hash("123","XO*7ps");
        System.out.println(md5Hash1.toHex());
//使用md5+sa1t+hash散列
        Md5Hash md5Hash2 =new Md5Hash("123","XO*7ps",1024);
        System.out.println(md5Hash2.toHex());

    }
}

 获取加密后的密码,接下来测试md5、md5+salt、md5+salt+hash

package com.hzw.shiro.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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import javax.annotation.Resource;

public class CustomerMd5Realm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取身份信息
        String principal = (String) token.getPrincipal();
        //根据用户名
        if ("hzw".equals(principal)) {
            //
            return new SimpleAuthenticationInfo(
                    principal,
                    "202cb962ac59075b964b07152d234b70",
                   // ByteSource.Util.bytes("XO*7ps"),  //+salt 密文
                    this.getName());
        }
        return null;
    }
}

自定义Realm

package com.hzw.shiro;

import com.hzw.shiro.realm.CustomerMd5Realm;
import com.hzw.shiro.realm.CustomerRealm;
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.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;

public class MD5Authenit {
    public static void main(String[] args) {
        //1.创建安全管理器对象 ctrl +h 看结构图
        DefaultSecurityManager securityManager=new  DefaultSecurityManager();
        //2.自定义Realm
        CustomerMd5Realm md5Realm = new CustomerMd5Realm();
        //设置realm 使用hash凭借匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //使用算法
        credentialsMatcher.setHashAlgorithmName("md5");
        //hash列
      //  credentialsMatcher.setHashIterations(1024);
        //set进去
        md5Realm.setCredentialsMatcher(credentialsMatcher);
        securityManager.setRealm(md5Realm);

        //3.SecurityUtils 全局安全工具类设置安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        //4.Subject:主体
        Subject subject = SecurityUtils.getSubject();
        //5创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("hzw", "123");
        try {
            //登录
            subject.login(token);
            System.out.println("登录成功");
        } catch ( UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名不存在");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误");
        }
    }
}

测试md5

5.shiro中的授权

5.1授权


授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没
有权限是无法访问的。


5.2关键对象


授权可简单理解为who对what(which)进行How操作
Who,即主体(Subject),主体需要访问系统中的资源。
What,即资源(Resource),如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型资源实例,比如商品信息为资源类型,类型为t01的商品为资源实例,编号为001的商品信息也属于资源实例。
HoW,权限/许可(Permission),规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可。

5.3授权流程

 5.4授权方式

5.5权限字符串


权限字符串的规则是:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用通配符。
例子:
·用户创建权限:user:create,或user:create:*
·用户修改实例001的权限:user:update:001
·用户实例001的所有权限:user:*:001

5.6 shiro中授权编程实现方式

 5.7开发授权

//shiro所需依赖

    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.3.2</version>
    </dependency>

//自定义realm

package com.hzw.shiro.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;

import javax.annotation.Resource;

public class CustomerMd5Realm extends AuthorizingRealm {
   //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String principal = (String) principals.getPrimaryPrincipal();
        System.out.println("身份信息"+principal);
        //根据身份信息 用户名 获取当前用户的角色信息, 以及权限信息 xiaoehen admin user
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //将数据库查询角色信息赋值给权限对象
        simpleAuthorizationInfo.addRole("admin");
        simpleAuthorizationInfo.addRole("user");
        //将数据库中查询权限信息赋值给权限对象
        simpleAuthorizationInfo.addStringPermission("user:*:01");
        simpleAuthorizationInfo.addStringPermission("produce:create");


        return simpleAuthorizationInfo;
    }
//认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取身份信息
        String principal = (String) token.getPrincipal();
        //根据用户名
        if ("hzw".equals(principal)) {
            //参数1:数据库用户名参数2:数据库md5+salt之后的密码参数3:注册时的随机盐参数4:realm的名字
            return new SimpleAuthenticationInfo(
                    principal,
                    "908da6d8e6057542323d9f58de42f9ab",
                    ByteSource.Util.bytes("XO*7ps"),  //+salt 密文
                    this.getName());
        }
        return null;
    }
}

//

package com.hzw.shiro;

import com.hzw.shiro.realm.CustomerMd5Realm;
import com.hzw.shiro.realm.CustomerRealm;
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.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;

import java.util.Arrays;

public class MD5Authenit {
    public static void main(String[] args) {
        //1.创建安全管理器对象 ctrl +h 看结构图
        DefaultSecurityManager securityManager=new  DefaultSecurityManager();
        //2.自定义Realm
        CustomerMd5Realm md5Realm = new CustomerMd5Realm();
        //设置realm 使用hash凭借匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //使用算法
        credentialsMatcher.setHashAlgorithmName("md5");
        //hash列
       credentialsMatcher.setHashIterations(1024);
        //set进去
        md5Realm.setCredentialsMatcher(credentialsMatcher);
        securityManager.setRealm(md5Realm);

        //3.SecurityUtils 全局安全工具类设置安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        //4.Subject:主体
        Subject subject = SecurityUtils.getSubject();
        //5创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("hzw", "123");
        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("====单角色====");
            System.out.println(subject.hasRole("admin"));
            System.out.println("====多角色====");
        //基于多角色权限控制
            System.out.println(subject.hasAllRoles(Arrays.asList("admin", "user")));
            System.out.println("====是否具有其中一个角色====");
        //是否具有其中一个角色
           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:*:01"));
        System.out.println("权限:"+subject.isPermitted("produce:create:01"));
        //分别具有哪些权限
        boolean[] permitted = subject.isPermitted("user:*:01", "user:*:04");
        for (boolean b : permitted) {
            System.out.println(b);
        }
        //同时具有哪些权限
        System.out.println("===同时具有哪些权限===");
        boolean permittedAll = subject.isPermittedAll("user:*:01", "produce:create:01");
        System.out.println(permittedAll);
    }
}

6基于SpringBoot整合

整合思路

创建springboot项目

6.1引入shiro依赖

<!--引入jsp解析-->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <!--引入shiro整合springboot依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.5.3</version>
        </dependency>

6.2配置shiro环境

1.创建shiro配置类

1.1配置ShiroFilterFactoryBean

1.2配置DefaultWebSecurityManager

1.4自定义Realm

package com.hzw.config;

import com.hzw.shiro.CustomerRealm;
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;

@Configuration
public class ShiroConfig  {
    //1.创建shiroFilter所有拦截请求
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //给filter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //配置系统受限资源
        //配置系统公共资源
        HashMap<String, String> map = new HashMap<>();
        map.put("/index.jsp","authc");  //authc 请求这个资源要认证和授权

        //默认认证界面路径
        shiroFilterFactoryBean.setLoginUrl("/login.jsp");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;

    }
    //2.创建安全管理器
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //给安全管理器设置
        defaultWebSecurityManager.setRealm(realm);
        return defaultWebSecurityManager;
    }

    //3.创建自定义realm
    @Bean
    public Realm realm(){
        CustomerRealm customerRealm = new CustomerRealm();
        return customerRealm;
    }


}

1.3创建自定义shiro

package com.hzw.shiro;
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;
public class CustomerRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("================");
        String principal = (String)token.getPrincipal();
        if ("hzw".equals(principal)){
            return new SimpleAuthenticationInfo(principal,"123",this.getName());
        }
        return null;
    }
}

1.5编写控制器跳转至index.html

package com.hzw.controller;
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.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {

    @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){
        //获取主题对象
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(new UsernamePasswordToken(username,password));
            return "redirect:/index.jsp";
        }catch (UnknownAccountException e){
            e.getStackTrace();
            System.out.println("用户名错误");
        }catch (IncorrectCredentialsException e){
            e.getStackTrace();
            System.out.println("密码错误");
        }
        return "redirect:/login.jsp";
    }
}

index.jsp

<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<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>首页</title>
</head>
<body>
<h1>系统主页</h1>
<a href="${pageContext.request.contextPath}/user/login">退出登录</a>
<ul style="list-style: none">
    <li><a href="">用户管理</a></li>
    <li><a href="">商品管理</a></li>
    <li><a href="">订单管理</a></li>
    <li><a href="">物流管理</a></li>
</ul>
</body>
</html>

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>
<h2>VIP用户登录</h2>
<form action="${pageContext.request.contextPath}/user/logout" method="post">
    用户名:<input type="text" name="username"><br/>
    密码:<input type="text" name="password"><br/>
    <input type="submit" value="登录">
</form>
</body>
</html>

1.6启动测试

登录 输入正确密码 跳转到index.jsp

1.7加入权限控制

package com.hzw.config;

import com.hzw.shiro.CustomerRealm;
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;

@Configuration
public class ShiroConfig  {
    //1.创建shiroFilter所有拦截请求
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //给filter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        HashMap<String, String> map = new HashMap<>();
        //配置系统公共资源
        map.put("/user/login","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();
        //给安全管理器设置
        defaultWebSecurityManager.setRealm(realm);
        return defaultWebSecurityManager;
    }

    //3.创建自定义realm
    @Bean
    public Realm realm(){
        CustomerRealm customerRealm = new CustomerRealm();
        return customerRealm;
    }


}

6.4常见过滤器

6.3MD5、Salt的认证实现 

1.开发数据库注册

0  开发注册界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>用户注册</h1>
<form action="${pageContext.request.contextPath}/user/register" method="post">
    用户名:<input type="text" name="username"><br/>
    密码:  <input type="text" name="password" ><br/>
    <input type="submit" value="用户注册">

</form>
</body>
</html>

1.创建数据库表结构

2.引入依赖

<!--引入jsp解析-->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <!--引入shiro整合springboot依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.5.3</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
   

 

3.配置application.properties配置文件

server.port=8888
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.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
mybatis.type-aliases-package=com.hzw.entry
mybatis.mapper-locations=classpath:com/hzw/mapper/*.xml
logging.level.com.hzw.dao=debug

4.创建entry

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String username;
    private String password;
    private String salt;
}

5.创建dao接口


import com.hzw.entry.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserDao {
    //保存
    void save(User user);
    //根据用户名查询业务的方法
    User findByUserName(String username);
}

6.开发mappper配置文件

<?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.hzw.dao.UserDao">

    <insert id="save" parameterType="com.hzw.entry.User" useGeneratedKeys="true" keyProperty="id">
      insert into user(username,password,salt) values (#{username},#{password},#{salt})
    </insert>
    <select id="findByUserName" resultType="com.hzw.entry.User" parameterType="String">
        select id,username,password,salt from user
        where username=#{username}
    </select>

</mapper>

7.开发service接口和实现类

import com.hzw.entry.User;

public interface UserService {
    //注册用户方法
    void register(User user);
    //根据用户名查询业务的方法
    User findByUserName(String username);
}
package com.hzw.service.impl;

import com.hzw.dao.UserDao;
import com.hzw.entry.User;
import com.hzw.service.UserService;
import com.hzw.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;

@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Override
    public void register(User user) {
        //1.生成salt
        String salt = SaltUtils.getSalt(8);
        System.out.println(salt);
        //2.保存
        user.setSalt(salt);
        //3.明文密码:md5+salt+hash
        Md5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024);
        user.setPassword(md5Hash.toHex());
        System.out.println(md5Hash);
        userDao.save(user);
    }

    @Override
    public User findByUserName(String username) {
        return userDao.findByUserName(username);
    }

}

8.创建utils工具类

//获取salt随机盐

import java.util.Random;

public class SaltUtils {

    public static String getSalt(int n){
        char[] chars="ABCDEFGHIJKLMNOPORSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#&*()".toCharArray();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i <n ; i++) {
            char aChar=chars[new Random().nextInt(chars.length)];
            stringBuilder.append(aChar);
        }
        return stringBuilder.toString();
    }

    public static void main(String[] args) {
        String salt = getSalt(8);
        System.out.println(salt);
    }

}

//根据bean名字获取bean对象

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class AppliactionContextUtils implements ApplicationContextAware {
    private static ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context=applicationContext;

    }
    //根据bean名字获取工厂指定bean对象
    public  static Object getBean(String beanName){
        Object bean = context.getBean(beanName);
        return bean;
    }
}

9.解密 密文 避免登录失败 因为密码与数据库密码不一致

import com.hzw.shiro.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;

@Configuration
public class ShiroConfig  {
    //1.创建shiroFilter所有拦截请求
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //给filter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        HashMap<String, String> map = new HashMap<>();
        map.put("/user/login","anon");         //配置系统公共资源
        map.put("/user/register","anon");         //配置系统公共资源
        map.put("/register.jsp","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();
        //给安全管理器设置
        defaultWebSecurityManager.setRealm(realm);
        return defaultWebSecurityManager;
    }

    //3.创建自定义realm
    @Bean
    public Realm realm(){
        CustomerRealm customerRealm = new CustomerRealm();
        //hash凭证校验匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法为MD5
        credentialsMatcher.setHashAlgorithmName("MD5");
        //设置散列次数
        credentialsMatcher.setHashIterations(1024);
        customerRealm.setCredentialsMatcher(credentialsMatcher);
        return customerRealm;
    }


}

9自定义realm

package com.hzw.shiro;
import com.hzw.entry.User;
import com.hzw.service.UserService;
import com.hzw.utils.AppliactionContextUtils;
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;
public class CustomerRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("================");
        //根据
        String principal = (String)token.getPrincipal();
        UserService userService =(UserService)AppliactionContextUtils.getBean("userService");
        User user = userService.findByUserName(principal);
        System.out.println(principal);
        if (!ObjectUtils.isEmpty(user)){
            return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),ByteSource.Util.bytes(user.getSalt()),this.getName());
        }
        return null;
    }
}

10.开发controller

package com.hzw.controller;
import com.hzw.entry.User;
import com.hzw.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;
@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";
        }
    }
    /**
     * 退出登录
     * @return
     */
    @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){
        //获取主题对象
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(new UsernamePasswordToken(username,password));
            return "redirect:/index.jsp";
        }catch (UnknownAccountException e){
            e.getStackTrace();
            System.out.println("用户名错误");
        }catch (IncorrectCredentialsException e){
            e.getStackTrace();
            System.out.println("密码错误");
        }
        return "redirect:/login.jsp";
    }
}

11.密文加密 运行成功

6.4shiro中授权编程实现方式-代码实现

编程和注解方式

package com.hzw.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("order")
public class ShiroController {
    //使用注解来判断是否具有权限
    @RequestMapping("save")
    //@RequiresRoles("user")   //用来判断角色 具有user
    @RequiresRoles({"user,admin"})  //用来判断角色 同时具有多个角色
    @RequiresPermissions("user:update:01")  //用来判断权限字符串
    public String save(){
        Subject subject = SecurityUtils.getSubject();
        //编程
        if (subject.hasRole("user")){
            System.out.println("保存成功");
        }else {
            System.out.println("无权访问");
        }

      return "redirect:/index.jsp";
    }

}

3.标签

加上shiro标签头

<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!doctype html>
<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>首页</title>
</head>
<body>
<h1>系统主页</h1>
<a href="${pageContext.request.contextPath}/user/logout">退出登录</a>
<ul style="list-style: none">
    <%--角色授权--%>
    <shiro:hasRole name="user">
        <li><a href="">用户管理</a></li>
        <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="user:find:*">
                <li><a href="">查询</a></li>
            </shiro:hasPermission>
        </ul>
    </shiro:hasRole>
    <shiro:hasRole name="admin">
        <li><a href="">商品管理</a></li>
        <li><a href="">订单管理</a></li>
        <li><a href="">物流管理</a></li>
    </shiro:hasRole>

</ul>
</body>
</html>

6.5.shiro整合springboot之授权数据的数据库获取

数据库表设计

准备五张表,两张中间表

sql语句

/*
SQLyog Ultimate v12.09 (64 bit)
MySQL - 8.0.11 : 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 `pers` */

DROP TABLE IF EXISTS `pers`;

CREATE TABLE `pers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(40) DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

/*Data for the table `pers` */

insert  into `pers`(`id`,`name`,`url`) values (1,'user:*:*',NULL),(2,'product:*:*',NULL),(3,'order:*:*',NULL);

/*Table structure for table `role` */

DROP TABLE IF EXISTS `role`;

CREATE TABLE `role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(40) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

/*Data for the table `role` */

insert  into `role`(`id`,`name`) values (1,'user'),(2,'admin'),(3,'produce');

/*Table structure for table `role_perms` */

DROP TABLE IF EXISTS `role_perms`;

CREATE TABLE `role_perms` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `roleid` int(6) DEFAULT NULL,
  `permsid` int(6) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

/*Data for the table `role_perms` */

insert  into `role_perms`(`id`,`roleid`,`permsid`) values (1,1,1),(2,1,2),(3,2,1),(4,3,2),(5,2,3);

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `password` varchar(40) DEFAULT NULL,
  `username` varchar(10) DEFAULT NULL,
  `salt` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

/*Data for the table `user` */

insert  into `user`(`id`,`password`,`username`,`salt`) values (1,'aa337c0f7ba12939db8998b3a4b15eb3','ryw','pLEJ3#1P'),(2,'136c2118bc6716fbd8bdf59df815956f','hzw01','dhh8e1RN');

/*Table structure for table `user_role` */

DROP TABLE IF EXISTS `user_role`;

CREATE TABLE `user_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userid` int(6) DEFAULT NULL,
  `roleid` int(6) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

/*Data for the table `user_role` */

insert  into `user_role`(`id`,`userid`,`roleid`) values (1,1,1),(2,2,2),(3,2,3),(4,2,1);

/*!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 */;

 entry实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class Pers {
    private Integer id;
    private String name;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.List;

@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class Role {
    private Integer id;
    private String name;

    private List<Pers> pers;
}

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.List;

@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String username;
    private String password;
    private String salt;
    private List<Role> roles;
}

UserDao接口

import com.hzw.entry.Pers;
import com.hzw.entry.User;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface UserDao {
    //保存
    void save(User user);
    //根据用户名查询业务的方法
    User findByUserName(String username);
    //根据用户名查询所有角色
    User findRolesByUserName(String username);
    //根据角色id查询权限集合
    List<Pers> findPermsByRoleId(Integer id);
}

mapper配置

<?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.hzw.dao.UserDao">

    <insert id="save" parameterType="com.hzw.entry.User" useGeneratedKeys="true" keyProperty="id">
      insert into user(username,password,salt) values (#{username},#{password},#{salt})
    </insert>
    <select id="findByUserName" resultType="com.hzw.entry.User" parameterType="String">
        select id,username,password,salt from user
        where username=#{username}
    </select>
    <resultMap id="userMap" type="com.hzw.entry.User">
        <id column="uid" property="id"></id>
        <result column="username" property="username"/>
        <collection property="roles" javaType="list" ofType="com.hzw.entry.Role">
            <id column="rid" property="id"></id>
            <result column="name" property="name"></result>
        </collection>
    </resultMap>

    <select id="findRolesByUserName" parameterType="String" resultMap="userMap">
        SELECT u.`id` uid,u.`username`,r.`id` rid,r.`name`
        FROM USER u
        LEFT JOIN `user_role` ur
        ON u.`id`=ur.`userid`
        LEFT JOIN role r
        ON ur.`roleid`=r.`id`
        WHERE u.`username`=#{username}

    </select>
    <select id="findPermsByRoleId" resultType="com.hzw.entry.Pers">
        SELECT p.id,p.name,p.url,r.`name`
        FROM role r
        LEFT JOIN role_perms rp
        ON r.id=rp.roleid
        LEFT JOIN pers p
        ON p.id=rp.permsid
        WHERE r.id=#{id}
    </select>
</mapper>

配置类 application.properties

<?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.hzw.dao.UserDao">

    <insert id="save" parameterType="com.hzw.entry.User" useGeneratedKeys="true" keyProperty="id">
      insert into user(username,password,salt) values (#{username},#{password},#{salt})
    </insert>
    <select id="findByUserName" resultType="com.hzw.entry.User" parameterType="String">
        select id,username,password,salt from user
        where username=#{username}
    </select>
    <resultMap id="userMap" type="com.hzw.entry.User">
        <id column="uid" property="id"></id>
        <result column="username" property="username"/>
        <collection property="roles" javaType="list" ofType="com.hzw.entry.Role">
            <id column="rid" property="id"></id>
            <result column="name" property="name"></result>
        </collection>
    </resultMap>

    <select id="findRolesByUserName" parameterType="String" resultMap="userMap">
        SELECT u.`id` uid,u.`username`,r.`id` rid,r.`name`
        FROM USER u
        LEFT JOIN `user_role` ur
        ON u.`id`=ur.`userid`
        LEFT JOIN role r
        ON ur.`roleid`=r.`id`
        WHERE u.`username`=#{username}

    </select>
    <select id="findPermsByRoleId" resultType="com.hzw.entry.Pers">
        SELECT p.id,p.name,p.url,r.`name`
        FROM role r
        LEFT JOIN role_perms rp
        ON r.id=rp.roleid
        LEFT JOIN pers p
        ON p.id=rp.permsid
        WHERE r.id=#{id}
    </select>
</mapper>

jsp

index.jsp 首页

<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!doctype html>
<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>首页</title>
</head>
<body>
<h1>系统主页</h1>
<a href="${pageContext.request.contextPath}/user/logout">退出登录</a>
<ul style="list-style: none">
    <%--角色授权--%>
    <shiro:hasRole name="user">
        <li><a href="">用户管理</a></li>
        <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>
    </shiro:hasRole>
    <shiro:hasRole name="admin">
        <li><a href="">商品管理</a></li>
        <li><a href="">订单管理</a></li>
        <li><a href="">物流管理</a></li>
    </shiro:hasRole>

</ul>
</body>
</html>

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>
<h2>VIP用户登录</h2>
<form action="${pageContext.request.contextPath}/user/login" method="post">
    用户名:<input type="text" name="username"><br/>
    密码:  <input type="password" name="password" ><br/>
    <input type="submit" value="登录">
</form>
</body>
</html>

register.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>用户注册</h1>
<form action="${pageContext.request.contextPath}/user/register" method="post">
    用户名:<input type="text" name="username"><br/>
    密码:  <input type="text" name="password" ><br/>
    <input type="submit" value="用户注册">

</form>
</body>
</html>

Service接口和实现类

import java.util.List;
public interface UserService {
    //注册用户方法
    void register(User user);
    //根据用户名查询业务的方法
    User findByUserName(String username);
    //根据用户名查询所有角色
    User findRolesByUserName(String username);
    //根据角色id查询权限集合
    List<Pers> findPermsByRoleId(Integer id);
}
package com.hzw.service.impl;
import com.hzw.dao.UserDao;
import com.hzw.entry.Pers;
import com.hzw.entry.User;
import com.hzw.service.UserService;
import com.hzw.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;
import java.util.List;
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Override
    public void register(User user) {
        //1.生成salt
        String salt = SaltUtils.getSalt(8);
        System.out.println(salt);
        //2.保存
        user.setSalt(salt);
        //3.明文密码:md5+salt+hash
        Md5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024);
        user.setPassword(md5Hash.toHex());
        System.out.println(md5Hash);
        userDao.save(user);
    }
    @Override
    public User findByUserName(String username) {
        return userDao.findByUserName(username);
    }
    @Override
    public User findRolesByUserName(String username) {
        return userDao.findRolesByUserName(username);
    }

    @Override
    public List<Pers> findPermsByRoleId(Integer id) {
        return userDao.findPermsByRoleId(id);
    }

}

自定义Shiro

package com.hzw.shiro;
import com.hzw.entry.Pers;
import com.hzw.entry.Role;
import com.hzw.entry.User;
import com.hzw.service.UserService;
import com.hzw.utils.AppliactionContextUtils;
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;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.List;

public class CustomerRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
       //获取身份信息
        String primaryPrincipal = (String) principal.getPrimaryPrincipal();
        System.out.println("调用授权验证:"+primaryPrincipal);
       //根据主身份获取角色和权限信息
        UserService userService =(UserService)AppliactionContextUtils.getBean("userService");
        User user = userService.findRolesByUserName(primaryPrincipal);
        //授权信息
        if (user.getRoles()!=null){
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            for (Role role : user.getRoles()) {
                simpleAuthorizationInfo.addRole(role.getName());
                //权限信息
                List<Pers> perms = userService.findPermsByRoleId(role.getId());
                if (!CollectionUtils.isEmpty(perms)){
                    for (Pers perm : perms) {
                        simpleAuthorizationInfo.addStringPermission(perm.getName());
                    }
                }
            }
            return simpleAuthorizationInfo;
        }
        return null;
    }
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("================");
        //获取身份信息
        String principal = (String)token.getPrincipal();
        UserService userService =(UserService)AppliactionContextUtils.getBean("userService");
        User user = userService.findByUserName(principal);
        System.out.println(principal);
        if (!ObjectUtils.isEmpty(user)){
            return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),ByteSource.Util.bytes(user.getSalt()),this.getName());
        }
        return null;
    }
}

shiro拦截器

package com.hzw.config;

import com.hzw.shiro.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;

@Configuration
public class ShiroConfig  {
    //1.创建shiroFilter所有拦截请求
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //给filter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        HashMap<String, String> map = new HashMap<>();
        map.put("/user/login","anon");         //配置系统公共资源
        map.put("/user/register","anon");         //配置系统公共资源
        map.put("order/save","anon");
        map.put("/register.jsp","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();
        //给安全管理器设置
        defaultWebSecurityManager.setRealm(realm);
        return defaultWebSecurityManager;
    }

    //3.创建自定义realm
    @Bean
    public Realm realm(){
        CustomerRealm customerRealm = new CustomerRealm();
        //hash凭证校验匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法为MD5
        credentialsMatcher.setHashAlgorithmName("MD5");
        //设置散列次数
        credentialsMatcher.setHashIterations(1024);
        customerRealm.setCredentialsMatcher(credentialsMatcher);
        return customerRealm;
    }


}

controller

package com.hzw.controller;
import com.hzw.entry.User;
import com.hzw.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;
@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";
        }
    }
    /**
     * 退出登录
     * @return
     */
    @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){
        //获取主题对象
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(new UsernamePasswordToken(username,password));
            return "redirect:/index.jsp";
        }catch (UnknownAccountException e){
            e.getStackTrace();
            System.out.println("用户名错误");
        }catch (IncorrectCredentialsException e){
            e.getStackTrace();
            System.out.println("密码错误");
        }
        return "redirect:/login.jsp";
    }
}

utils工具

获取随机盐

package com.hzw.utils;

import java.util.Random;

public class SaltUtils {

    public static String getSalt(int n){
        char[] chars="ABCDEFGHIJKLMNOPORSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#&*()".toCharArray();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i <n ; i++) {
            char aChar=chars[new Random().nextInt(chars.length)];
            stringBuilder.append(aChar);
        }
        return stringBuilder.toString();
    }

    public static void main(String[] args) {
        String salt = getSalt(8);
        System.out.println(salt);
    }

}

通过bean名字获取bean对象

package com.hzw.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class AppliactionContextUtils implements ApplicationContextAware {
    private static ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context=applicationContext;

    }
    //根据bean名字获取工厂指定bean对象
    public  static Object getBean(String beanName){
        Object bean = context.getBean(beanName);
        return bean;
    }
}

测试

user 用户管理的查询操作  需要有order.*.*资源权限

测试截图  user没有查询的操作 

 admin 拥有全部操作权限

 6.8使用CacheManager
1.Cache作用


Cache缓存:计算机内存中一段数据内存条
作用:用来减轻DB的访问压力,从而提高系统的查询效率
流程:

 2.使用shiro中默认EhCache实现缓存

开启依赖

 <!--引入shiro和ehcache-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>

2.开启cache管理

//3.创建自定义realm
    @Bean
    public Realm realm(){
        CustomerRealm customerRealm = new CustomerRealm();
        //hash凭证校验匹配器
        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;
    }

6.9Shiro整合springboot缓存之Redis

1.导入data-redis依赖

  <!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

2.自定义redis缓存实现

package com.hzw.shiro.cache;

import com.hzw.utils.AppliactionContextUtils;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.util.Collection;
import java.util.Set;

//自定义redis缓存实现
public class RedisCache<k,v> implements Cache<k,v> {
   private String cacheName;
   public RedisCache(){
   }

    public RedisCache(String cacheName) {
        this.cacheName = cacheName;
    }

    @Override
    public v get(k k) throws CacheException {
        System.out.println("get key:"+k);
        return(v) getRedisTemplate().opsForHash().get(this.cacheName,k.toString());
    }

    @Override
    public v put(k k, v v) throws CacheException {
        System.out.println("put key:"+k);
        System.out.println("put value:"+v);
        getRedisTemplate().opsForHash().put(this.cacheName,k.toString(),v);
        return null;
    }

    @Override
    public v remove(k k) throws CacheException {

        return (v) getRedisTemplate().opsForHash().delete(this.cacheName,k.toString());
    }

    @Override
    public void clear() throws CacheException {
       getRedisTemplate().delete(this.cacheName);

    }

    @Override
    public int size() {
        return getRedisTemplate().opsForHash().size(this.cacheName).intValue();
    }

    @Override
    public Set<k> keys() {
        return getRedisTemplate().opsForHash().keys(this.cacheName);
    }

    @Override
    public Collection<v> values() {
        return getRedisTemplate().opsForHash().values(this.cacheName);
    }
    private static RedisTemplate getRedisTemplate(){
        RedisTemplate redisTemplate = (RedisTemplate)AppliactionContextUtils.getBean("redisTemplate");
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

3.自定义RedisCacheManager 实现CacheManager

package com.hzw.shiro.cache;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
public class RedisCacheManager implements CacheManager {
    //参数1:认证或者是授权缓存的统一名称
    @Override
    public <K, V> Cache<K, V> getCache(String cacheName) throws CacheException {
        System.out.println(cacheName);
        return new RedisCache<K,V>(cacheName);
    }
}

4.在shiroconfig 将EnCache修改为自定义RedisCacheManager开启缓存管理

 //3.创建自定义realm
    @Bean
    public Realm realm(){
        CustomerRealm customerRealm = new CustomerRealm();
        //hash凭证校验匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法为MD5
        credentialsMatcher.setHashAlgorithmName("MD5");
        //设置散列次数
        credentialsMatcher.setHashIterations(1024);
        customerRealm.setCredentialsMatcher(credentialsMatcher);
        //开启缓存管理
        customerRealm.setCacheManager(new RedisCacheManager());
        customerRealm.setCachingEnabled(true);  //开启全局缓存
        customerRealm.setAuthenticationCachingEnabled(true); //开启认证缓存
        customerRealm.setAuthenticationCacheName("authenticationCache");
        customerRealm.setAuthorizationCachingEnabled(true); //开启授权缓存
        customerRealm.setAuthorizationCacheName("authorizationCache");
        return customerRealm;
    }

5.随机盐序列化 自定义类 实现ByteSource

package com.hzw.shiro;

import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.CodecSupport;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.util.ByteSource;
import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Arrays;
//自定义随机盐转化
public class MyBateSource implements ByteSource,Serializable{
    private byte[] bytes;
    private String cachedHex;
    private String cachedBase64;
    public MyBateSource(){

    }
    public MyBateSource(byte[] bytes) {
        this.bytes = bytes;
    }

    public MyBateSource(char[] chars) {
        this.bytes = CodecSupport.toBytes(chars);
    }

    public MyBateSource(String string) {
        this.bytes = CodecSupport.toBytes(string);
    }

    public MyBateSource(ByteSource source) {
        this.bytes = source.getBytes();
    }

    public MyBateSource(File file) {
        this.bytes = (new MyBateSource.BytesHelper()).getBytes(file);
    }

    public MyBateSource(InputStream stream) {
        this.bytes = (new MyBateSource.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);
        }
    }
}

5.CustomerRealm  new MyBateSource(user.getSalt())

@Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("================");
        //获取身份信息
        String principal = (String)token.getPrincipal();
        UserService userService =(UserService)AppliactionContextUtils.getBean("userService");
        User user = userService.findByUserName(principal);
        System.out.println(principal);
        if (!ObjectUtils.isEmpty(user)){
            return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),new MyBateSource(user.getSalt()),this.getName());
        }
        return null;
    }
}

6.各实体类都需要实现序列化

Pers

Role

User

测试结果可以看出登录账号从redis里取shiro缓存信息

7.Shiro整合springboot之thymeleaf权限控制
1.引入扩展依赖

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/104068.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java ssm羽毛球馆管理和交流平台系统

羽毛球作为每个人爱好的一项体育运动&#xff0c;越来也收到人们的好评和关注。很多羽毛球爱好者通过网站的形式对羽毛球场地情况&#xff0c;羽毛球的爱好者的互相学习进行交流&#xff0c;方便了大众对于羽毛球的交流和沟通&#xff0c;提高羽毛球技术的同时&#xff0c;也让…

颠覆传统返利模式,针对用户复购率低的全新解决方案——消费盲返

如今互联网商业模式遍地开花&#xff0c;谈及商业模式&#xff0c;大家第一想到的肯定是积分消费返利&#xff0c;那么“消费返利”对于大家来说都不陌生&#xff0c;那么本期林工想给大家介绍的是一个怎么听怎么亏&#xff0c;实则已经悄悄爆火的模式——消费盲返&#xff0c;…

DNS寻址过程

文章目录什么是DNS寻址过程图显示什么是DNS DNS是域名系统( Domain Name System)的英文缩写&#xff0c;是一种组织成域层次结构的计算机和网络服务命名系统&#xff0c;它用于TCP/IP网络&#xff0c;它所提供的服务是用来将主机名和域名转换为IP地址的工作。 寻址过程 本地…

【Linux】第三部分 Linux文件系统目录结构

【Linux】第三部分 Linux文件系统目录结构 文章目录【Linux】第三部分 Linux文件系统目录结构3. Linux文件系统目录结构总结3. Linux文件系统目录结构 可以右键打开终端 目录意义bin该目录存放的是经常使用到的命令&#xff0c;例如上图所示&#xff1a;cd &#xff0c; ls 等…

《计算机程序构造与解释》读书笔记(3)

文章目录1. 写在最前面2. 设计的取舍3. 赋值和局部状态3.1 局部状态变量3.2 引进赋值带来的利益3.3 引进赋值的代价3.3.1 同一和变化3.3.2 命令式程序设计的缺陷4. 求值的环境模型4.1 求值规则4.2 简单过程的应用4.3 将框架看做局部状态的展台4.4 内部定义5. 用变动数据做模拟5…

Mycat(13):全局表和普通表的配置和测试

1 全局表概述 一个真实的业务系统中&#xff0c;往往存在大量的类似字典表的表格&#xff0c;它们与业务表之间可能有关系&#xff0c;这种关系&#xff0c;可以理解为“标签”&#xff0c;而不应理解为通常的“主从关系”&#xff0c;这些表基本上很少变动&#xff0c;可以根…

Spring Security认证和授权

Spring Security认证和授权 一、Spring Security的认识 Spring Security是Spring家族中的一个安全管理框架。相比与另外一个安全框架Shiro&#xff0c;它提供了更丰富的功能&#xff0c;社区资源也比Shiro丰富。 一般来说中大型的项目都是使用SpringSecurity来做安全框架。小…

Windows C语言 UDP通信demo

目录编译环境快速入门编译指令服务端code客户端code参考文章以及遇到的问题编译环境 我的demo是通过此文章从C更改成的C&#xff0c;编译环境使用的是Mingw&#xff0c;如下图所示 快速入门 拷贝代码编译互传消息 编译指令 客户端&#xff1a;gcc .\udpclient.c -lwsock3…

《剑指offer》– 链表中倒数第k个节点、反转链表、合并两个排序的链表

一、链表中倒数时第k个节点&#xff1a; 1、题目&#xff1a; 输入一个链表&#xff0c;输出该链表中倒数第k个结点。 2、解题思路&#xff1a;单链表具有单向移动的特性。 &#xff08;1&#xff09;第一种&#xff1a;先遍历链表&#xff0c;算出链表节点数count&#xf…

计算机毕设Python+Vue学生用品采购系统(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

我国风电行业发展现状:并网装机容量持续增长 产业集中化趋势明显

根据观研报告网发布的《2022年中国风电行业分析报告-行业全景评估与投资规划分析》显示&#xff0c;风电是一种清洁、绿色的可再生能源。风力发电是能源领域中技术最成熟、最具规模开发条件和商业化发展前景的发电方式之一。发展风力发电对于解决能源危机、减轻环境污染、调整能…

【Java面试八股文宝典之基础篇】备战2023 查缺补漏 你越早准备 越早成功!!!——Day13

大家好&#xff0c;我是陶然同学&#xff0c;软件工程大三明年实习。认识我的朋友们知道&#xff0c;我是科班出身&#xff0c;学的还行&#xff0c;但是对面试掌握不够&#xff0c;所以我将用这100多天更新Java面试题&#x1f643;&#x1f643;。 不敢苟同&#xff0c;相信大…

【1760. 袋子里最少数目的球】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个整数数组 nums &#xff0c;其中 nums[i] 表示第 i 个袋子里球的数目。同时给你一个整数 maxOperations 。 你可以进行如下操作至多 maxOperations 次&#xff1a; 选择任意一个袋子&#…

开发板到货记录一波

今天在终于拿到了期待已久的开发板RK3568&#xff0c;来&#xff0c;亮个相吧&#xff01;&#xff01;&#xff01; 开发板资源还是相当丰富的&#xff0c;对于学习安卓&Linux都是非常友好的&#xff0c;开发板默认安装的是安卓11系统&#xff0c;由于经费问题目前还没有…

小米发明“永动机”:走路即可为智能设备充电

蓝牙耳机、智能智能手表、智能手环、智能眼镜、智能手机……随着科技的进步&#xff0c;越来越多的移动与可穿戴智能设备开始走进我们的生活&#xff0c;智能设备在给人们生活带来便利的同时&#xff0c;也带来了一些困惑&#xff0c;越来越多诸如手环、TWS耳机等智能穿戴设备&…

火热的元宇宙,成为未来趋势

近年来&#xff0c;中国在算力上突飞猛进&#xff0c;有望成为世界顶尖&#xff0c;再加数据和算法上的优势&#xff0c;中国就很有可能在元宇宙方面率先开发出原创性的技术&#xff0c;从而实现从“0”到“1”的突破。 元宇宙办公 在未来的元宇宙畅想中&#xff0c;人们不仅…

java Lambda表达式的标准格式及其前提带有(代码演示)

观看本文 首先 你要对Lambda的概念有个基本了解 对此 您可以先查看我的文章 java Lambda概念 通过实现线程简单体验一下Lambda表达式 跟着上一篇文章做 你的代码会是这样 new Thread( () ->{System.out.println("执行线程"); } ).start();而其中Lambda 表达式 则…

资产种类多数量大、使用地点分散?集中管理,一招搞定

随着银行规模不断壮大&#xff0c;资产数量也随之不断增加&#xff0c;同时银行资产具有总量大、价值高、使用地点分散、管理难度大的特点&#xff0c;IT资产、房产、办公用品、维修保养需求随着业务的快速增长对管理工作带来了压力。 传统资产管理4大痛点 01.账实不符 实物账…

【Python机器学习】神经网络中常用激活函数、损失函数、优化方法(图文解释 附源码)

下面以经典的分类任务&#xff1a;MNIST手写数字识别&#xff0c;采用全连接层神经网络 MNIST数据集是一个手写体的数字图片集&#xff0c;它包含有训练集和测试集&#xff0c;由250个人手写的数字构成。训练集包含60000个样本&#xff0c;测试集包含10000个样本。每个样本包括…

数据结构基础--散列表

一、散列简介 散列表&#xff0c;又叫哈希表&#xff08;Hash Table&#xff09;&#xff0c;是能够通过给定的关键字的值直接访问到具体对应的值的一个数据结构。也就是说&#xff0c;把关键字映射到一个表中的位置来直接访问记录&#xff0c;以加快访问速度。 通常&#xff0…