Shiro-编程不良人

(视频:哔哩哔哩-编程不良人

一:权限的管理(1~3)

1. 什么是权限管理:
在这里插入图片描述
3. 什么是身份认证:
在这里插入图片描述
5. 什么是授权:
在这里插入图片描述

二:什么是 Shiro(4~4)

1. 官网:https://shiro.apache.org/
2. 英文文档:https://shiro.apache.org/reference.html
3. 中文文档:http://greycode.github.io/shiro/doc/reference.html
在这里插入图片描述
在这里插入图片描述

三:Shiro 的核心架构(4~4)

1. Shiro 核心架构图:(视频p4:详解)
在这里插入图片描述
3. 模块解释说明:
在这里插入图片描述
在这里插入图片描述

四:Shiro中的认证(5~5)

1. 认证:
在这里插入图片描述
2. Shiro 中认证的关键对象:
在这里插入图片描述
3. 认证大体流程:
在这里插入图片描述
4. 认证的开发:
1)引入 shiro 依赖:

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.5.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.8.0</version>
        </dependency>

’ 2)创建:shiro.ini 文件

[users]
zhangsan=123456
lisi=123456
wangwu=123456
[users]
root = secret, admin
guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz
lonestarr = vespa, goodguy, schwartz

[roles]
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5

’ 3)完成认证:

    public static void main(String[] args) {
        //1:创建安全管理器
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        //2:给安全管理器设置 Realm
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        securityManager.setRealm(iniRealm);
        //3:给全局工具类,设置全局安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        //4:获取主体对象
        Subject subject = SecurityUtils.getSubject();
        //5:创建安全令牌
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("zhangsan", "123456");
        usernamePasswordToken.setRememberMe(true);
        try {
            subject.login(usernamePasswordToken);
        } catch (UnknownAccountException e) {
            System.out.println("账户错误:" + e);
        } catch (IncorrectCredentialsException e) {
            System.out.println("密码错误:" + e);
        }
        boolean authenticated = subject.isAuthenticated();
        System.out.println("用户是否登陆:" + authenticated);
        subject.logout();
        boolean authenticated2 = subject.isAuthenticated();
        System.out.println("用户是否登陆:" + authenticated2);
    }




5. 认证流程源码查看:
0)最终执行用户比较:SimpleAccountRealm。doGetAuthenticationInfo() 方法中完成用户名校验
0)最终密码校验是在 AuthenticatingRealm 中,assertCredentialsMatch()。
1)完成用户名校验:(SimpleAccountRealm)(方法中实现,可换成自己去读取数据库)
在这里插入图片描述
2)完成密码校验:(AuthenticatingRealm)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3)Realm 继承关系图:(自定义 Realm 继承 AuthorizingRealm 类)
在这里插入图片描述
在这里插入图片描述
4)以 SimpleAccountRealm 为例:
在这里插入图片描述
5)总结:

  • 1.AuthenticatingRealm --> 认证Realm–>doGetAuthenticationInfo()
  • 2.AuthorizingRealm --> 授权Realm --> getAuthorizationInfo()
  • 3.如果需要自定义 Realm,参考 SimpleAccountRealm 继承 AuthorizingRealm,才可覆盖认证、授权,两个方法。

6. 自定义 Realm 实现:( securityManager.setRealm(new MyRealm()); )
在这里插入图片描述

@Component
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private BlogUserService blogUserService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String principal = (String) token.getPrincipal();
        System.out.println("username:" + principal);
        //根据用户名查询数据库
        BlogUserEntity blogUserDB = blogUserService.getBlogUserByUsername(principal);
        if (!ObjectUtils.isEmpty(blogUserDB)) {
            //用户名、盐值、密码、//当前realm名称
            return new SimpleAuthenticationInfo(blogUserDB.getUsername(), "", blogUserDB.getPassword());
//          return new SimpleAuthenticationInfo(blogUserDB.getUsername(), blogUserDB.getPassword(), this.getName());
        }
        return null;
    }

}
    public static void main(String[] args) {
        SpringApplication.run(MyShiroDemo01Application.class, args);

        final Md5Hash md5Hash = new Md5Hash("123", "salt",1024);
        String resultStr = md5Hash.toHex();
        System.out.println(resultStr);

        // 1:创建 securityManager
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        // 2:设置自定义 Realm
        securityManager.setRealm(new MyRealm());
        // 3:通过安全工具类,设置安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        // 4:通过安全工具类,获取 subject 主体
        Subject subject = SecurityUtils.getSubject();
        // 5:创建 token
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("张三", "123");
        usernamePasswordToken.setRememberMe(true);
        // 6:登陆操作
        try {
            subject.login(usernamePasswordToken);
        } catch (UnknownAccountException e) {
            System.out.println("用户名出错");
        } catch (IncorrectCredentialsException e2) {
            System.out.println("密码出错");
        }
        System.out.println(subject.isAuthenticated());
    }



五:MD5 和 Salt 的简介和执行流程说明(6~9)

1. MD5 算法简介:
1)作用:一般用来加密、签名。
2)特点:MD5 算法不可逆,内容相同,无论执行多少次,结果始终一样。
3)结果:始终是一个 16进制,32位长度的字符串。
2. 使用:

		// 1:加盐
        final Md5Hash md5Hash = new Md5Hash("123", "salt");
        String resultStr = md5Hash.toHex();
        System.out.println(resultStr);

		// 2:加盐加散列
        final Md5Hash md5Hash = new Md5Hash("123", "salt", 1024);
        String resultStr = md5Hash.toHex();
        System.out.println(resultStr);

3. 实现:(使用自定义 Realm,加入:md5、salt、hash散列)
’ 0)凭证匹配器继承关系:在自定义 Realm 中,进行设定凭证匹配器。
在这里插入图片描述
’ 1)md5:

    public static void main(String[] args) {

        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        // 1、设置 Realm 为 Hash 凭证匹配器
        MyMd5Realm myMd5Realm = new MyMd5Realm();
		// 	2.1、自定义 Realm 设置,自定义凭证匹配器
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //  2.2、加密算法、散列次数
        matcher.setHashAlgorithmName("md5");
        matcher.setHashIterations(1024);
        // 	2.3、给自定义 Realm,设置自定义凭证匹配器
        myMd5Realm.setCredentialsMatcher(matcher);
        // 3:给安全管理器设置 Realm
        securityManager.setRealm(myMd5Realm);
		// 4:给全局工具类,设置安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        Subject subject = SecurityUtils.getSubject();
        // 5、创建 token
        UsernamePasswordToken token = new UsernamePasswordToken("张三", "123456");
        token.setRememberMe(true);
        try {
            subject.login(token);
            System.out.println(subject.isAuthenticated());
        } catch (UnknownAccountException e) {
            System.out.println("用户名错误");
        } catch (IncorrectCredentialsException e) {
            System.out.println("密码错误");
        }
    }
public class MyMd5Realm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String principal = (String) token.getPrincipal();
        System.out.println(principal);
        if ("张三".equals(principal)) {
            return new SimpleAuthenticationInfo(
            	"张三", 
            	"e10adc3949ba59abbe56e057f20f883e",
	            ByteSource.Util.bytes("sss"),
    	        this.getName());
        }
        return null;
    }

}

’ 2)md5 + 加随机盐值:

	/**
	* 参数:数据库用户名、数据库加密后的密码,
	* 		注册时的随机盐值、realm的名字;
	* 
	* 只需要加一次盐值,shiro会自动把用户输入密码加盐值。
	*/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String principal = (String) token.getPrincipal();
        System.out.println(principal);
        if ("张三".equals(principal)) {
        	// 用户名、密码,都为数据库中存储的加密后的
            return new SimpleAuthenticationInfo("张三",
                    "5194528bd63abca4bf9d09885bb425b7",
                    ByteSource.Util.bytes("sss"),
                    this.getName());
        }
        return null;
    }

‘ 3)md5 + 加随机盐值::(1024次)(除了上面加盐的地方,Realm声明散列次数)

        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        //设置 Realm 为 Hash 凭证匹配器
        MyMd5Realm myMd5Realm = new MyMd5Realm();
        //设置hash算法
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");
        matcher.setHashIterations(1024);
		// assertCredentialsMatch()方法,会获取默认凭证匹配器,
		// 所以,要先设置自定义凭证匹配器,放入hash算法规则
        myMd5Realm.setCredentialsMatcher(matcher);
        //设置Realm
        securityManager.setRealm(myMd5Realm);
        SecurityUtils.setSecurityManager(securityManager);



六:授权(10~11)

1. 授权:
在这里插入图片描述
3. 关键对象:
在这里插入图片描述
5. 授权流程:
在这里插入图片描述
7. 授权方式:
在这里插入图片描述
9. 权限字符串详解:
在这里插入图片描述
10. shiro 中授权编码实现方式
’ 1)编程式:
在这里插入图片描述
’ 2)注解式:
在这里插入图片描述
’ 3)标签式:
在这里插入图片描述
12. 角色管理:实际运用:
’ 1)验证完身份,给主体授权操作:

public class MyMd5Realm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //进行给当前主体授权
        HashSet<String> hashSet = new HashSet<>();
        hashSet.add("admin");
        hashSet.add("user");
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(hashSet);
        return simpleAuthorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        return null;
    }    
}

’ 2)验证主体是否有某种角色:(3种方法)

        //验证身份通过后,进行授权
        if (subject.isAuthenticated()) {
            //1.判断主体是否具有某个权限
            System.out.println(subject.hasRole("admin"));
            System.out.println(subject.hasRole("user"));
            //2.判断主体是否同时满足这两个条件
            System.out.println(subject.hasAllRoles(Arrays.asList("admin", "user")));
            //3.判断主体是否具有某个权限
            boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "user"));
            for (boolean b : booleans) {
                System.out.println(b);
            }
        }

14.(权限)基于权限字符串的访问控制:实际操作:
’ 1):(资源标识符:操作:资源类型)

public class MyMd5Realm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String primaryPrincipal = (String) principals.getPrimaryPrincipal();
        //可根据用户名,获取数据库的 角色信息、权限信息。

        //将数据库查询到 角色 信息,赋值给权限对象
        HashSet<String> hashSet = new HashSet<>();
        hashSet.add("admin");
        hashSet.add("user");
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(hashSet);
        //将数据库查询到 权限 信息,赋值给权限对象
        simpleAuthorizationInfo.addStringPermission("user:*:001");

        return simpleAuthorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        return null;
    }

}

’ 2)判断是否有权限:(权限验证)

        //验证身份通过后,进行验证
        if (subject.isAuthenticated()) {
            //1.基于权限字符串访问控制
            System.out.println(subject.isPermitted("user:*:*"));//false
            System.out.println(subject.isPermitted("user:*:001"));//true
            System.out.println(subject.isPermitted("user:update:001"));//true
            //2.同时具有哪些权限
             boolean permittedAll = subject.isPermittedAll("user:*:002", "user:*:001");
            System.out.println(permittedAll);//false
            //3.分别具有哪些权限
            boolean[] permitted = subject.isPermitted("user:*:002", "user:*:001");
            System.out.println(Arrays.toString(permitted));//[false, true]
        }



七:SpringBoot 整合 shiro 之 环境搭建(12~14)

1. 认证授权流程:
在这里插入图片描述
2. 创建springboot应用:
’ 1)整合 jsp 依赖:

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>

        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

’ 2)yml 配置:

server:
  port: 8080
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://114.215.173.88:3306/shiro-test-01
    username: root
    password: 123456
  mvc:
    view:
      prefix: /
      suffix: .jsp

mybatis:
  type-aliases-package: com.shiro.myshirodemo02jsp.entity
  mapper-locations: classpath:mapper/*.xml

’ 3)访问:http://localhost:8080/index.jsp
如果启动失败,需设置工作目录:
在这里插入图片描述

3. 配置 Shiro 相关:
’ 1)引入 springboot 整合 shiro 依赖:

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.5.3</version>
        </dependency>

’ 2)ShiroConfig:(3个 Bean 配置)

@Configuration
public class ShiroConfig {

	// 1:创建 shiro filter,//负责拦截所有请求
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 给 filter 设置 安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 设置拦截路径
        HashMap<String, String> filterMap = new HashMap<>();
        filterMap.put("/index.jsp", "authc");//authc:标识请求此资源需要认证和授权
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

        // 设置默认的认证界面路径
        shiroFilterFactoryBean.setLoginUrl("/login.jsp");        
        
        return shiroFilterFactoryBean;
    }

	// 2:创建 安全管理器
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(realm);
        return defaultWebSecurityManager;
    }
	
	// 3:创建 realm
    @Bean
    public Realm getRealm() {
        return new CustomerRealm();
    }

}

’ 3)MyRealm:

//自定义Realm
public class CustomerRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    	// 后面补充
        return null;
    }
}

’ 4)请求测试:(注:如使用 thymleaf,需要控制器跳转到页面)
访问:http://localhost:8080/index.jsp,跳转到登陆页面
在这里插入图片描述



八:整合 Shiro 之 认证和退出(15~15)

1. shiro 提供的 常见 过滤器:
在这里插入图片描述
2. 写登陆页面:

<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>登陆页面</title>
</head>
<body>
<h1>我的登陆页面</h1>
<form action="${pageContext.request.contextPath}/user/login" method="post">
    账号:<input type="text" name="username"><br>
    密码:<input type="text" name="password"><br>
    <input type="submit" value="登陆">
</form>
</body>
</html>

’ 4)controller:

@Controller
@RequestMapping(value = "/user")
public class ShiroController {

    @PostMapping(value = "/login")
    public String login(String username, String password) {
        System.out.println(username + ":" + password);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
        try {
            subject.login(usernamePasswordToken);
            return "redirect:/index.jsp";
        } catch (UnknownAccountException e) {
            System.out.println("账号错误");
        } catch (IncorrectCredentialsException e) {
            System.out.println("密码错误");
        }
        return "redirect:/login.jsp";
    }
}

’ 5)编写认证管理器:

//自定义Realm
public class MyRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        BlogUserEntity blogUserDB = shiroUserService.getUserByUsername(username);
        if (blogUserDB != null) {
            return new SimpleAuthenticationInfo(
                    blogUserDB.getUsername(),
                    blogUserDB.getPassword(),
                    this.getName());
        }
        return null;
    }
}

’ 6)退出登陆:
1.index.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>菜单页面</title>
</head>
<body>
<h1>菜单页面</h1>
<ul>
    <li><a href="">用户管理</a></li>
    <li><a href="">订单管理</a></li>
    <li><a href="">商品管理</a></li>
    <li><a href="">物流管理</a></li>
</ul>
<h1><a href="${pageContext.request.contextPath}/user/logout">退出登陆</a></h1>
</body>

’ 2.controller:

    @GetMapping(value = "/logout")
    public String logout() {
    	// 通过安全工具类,获取主体信息并登出
        Subject subject = SecurityUtils.getSubject();
        if (subject != null && subject.isAuthenticated()) {
            subject.logout();
        }
        return "redirect:/login.jsp";
    }





九:认证 + salt + 散列(16~17)

1. 创建数据库:

CREATE TABLE `blog_user` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `username` varchar(255) NOT NULL DEFAULT '' COMMENT '用户名',
  `password` varchar(255) NOT NULL DEFAULT '' COMMENT '密码',
  `salt` varchar(255) NOT NULL DEFAULT '' COMMENT '盐值',
  PRIMARY KEY (`id`)
);

在这里插入图片描述
3. mybatis 整合:
’ 1)相关依赖:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.6</version>
</dependency>

’ 2)相关配置:

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://114.215.173.88:3306/testdb
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource

mybatis:
  type-aliases-package: com.shiro.myshirodemo02jsp.entity
  mapper-locations: classpath:mybatis/mapper/*.xml

’ 3)mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.shiro.myshirodemo02jsp.dao.ShiroUserDao">

    <insert id="addUser">
        insert into blog_user (username, password, salt)
        values (#{username}, #{password}, #{salt})
    </insert>

    <select id="getUserByUsername" resultType="com.example.myshirodemo02testjsp.entity.BlogUserEntity">
        select *
        from blog_user
        where username = #{principal}
    </select>
</mapper>

5. 用户注册:
’ 1)jsp:

<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <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="用户注册"><br>
</form>
</body>
</html>

’ 2)controller:

@Controller
@RequestMapping(value = "/user")
public class ShiroController {

    @Autowired
    private ShiroUserService shiroUserService;

    @PostMapping(value = "/register")
    public String register(String username, String password) {
        System.out.println(username + ":" + password);
        
        Md5Hash newPassword = new Md5Hash(password, "salt", 1024);
        shiroUserService.addUser(username, newPassword.toHex(), "salt");
        return "redirect:/user/login.jsp";
    }

}

7. 用户登陆:(md5 + 随机盐 认证)
’ 1)修改 Realm 认证方式:

@Configuration
public class ShiroConfig {

    @Bean
    public Realm getRealm() {
        MyRealm myRealm = new MyRealm();
        //修改凭证校验匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("md5");
        credentialsMatcher.setHashIterations(1024);
        myRealm.setCredentialsMatcher(credentialsMatcher);
        return myRealm;
    }
}

’ 2)修改 :

    @Autowired
    private ShiroUserService shiroUserService;

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        BlogUserEntity blogUserDB = shiroUserService.getUserByUsername(username);
        if (blogUserDB != null) {
            return new SimpleAuthenticationInfo(
                    blogUserDB.getUsername(),
                    blogUserDB.getPassword(),
                    ByteSource.Util.bytes("salt"),
                    this.getName());
        }
        return null;
    }

’ 3)customerRealm 中,无法获取容器中 service 实例,解决方案。
i:增加工具类,用于获取容器中对象实例:

@Component
public class ApplicationContextUtils implements ApplicationContextAware {

    public static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

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

}

ii:修改 注入 service 方法:

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        // 获取容器中对象实例
        ShiroUserService shiroUserService = (ShiroUserService) ApplicationContextUtils.getBean("shiroUserServiceImpl");
        BlogUserEntity blogUserDB = shiroUserService.getUserByUsername(username);
        if (blogUserDB != null) {
            return new SimpleAuthenticationInfo(
                    blogUserDB.getUsername(),
                    blogUserDB.getPassword(),
                    ByteSource.Util.bytes("salt"),
                    this.getName());
        }
        return null;
    }





十:整合 shiro 之授权基本使用:(18~20)

1. 授权管理器编码:(基于角色权限管理)

@Component
public class MyRealm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String primaryPrincipal = (String) principals.getPrimaryPrincipal();
        //根据主体,获取角色信息,权限信息
        if ("zhangsan".equals(primaryPrincipal)) {
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            simpleAuthorizationInfo.addRole("admin");
            return simpleAuthorizationInfo;
        }
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        return null;
    }
}

3. index.jsp 页面控制:

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>菜单页面</title>
</head>
<body>
<h1>菜单页面</h1>
<ul>
    <shiro:hasAnyRoles name="admin,user">
        admin、user角色可以看到
        <li><a href="">用户管理</a></li>
    </shiro:hasAnyRoles>

    <shiro:hasRole name="user">
        admin 角色可以看到
        <li><a href="">订单管理</a></li>
        <li><a href="">商品管理</a></li>
        <li><a href="">物流管理</a></li>
    </shiro:hasRole>
    <li><a href="${pageContext.request.contextPath}/user/logout">退出登陆</a></li>
</ul>
</body>
</html>

5. 效果:
在这里插入图片描述
7. 基于权限字符串做权限管理:
’ 1)授权管理编码:

@Component
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private ShiroUserService shiroUserService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String primaryPrincipal = (String) principals.getPrimaryPrincipal();
        //根据主体,获取角色信息,权限信息
        if ("zhangsan".equals(primaryPrincipal)) {
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            simpleAuthorizationInfo.addRole("admin");

            //设置权限字符串           
			simpleAuthorizationInfo.addStringPermission("user:*:*");
            return simpleAuthorizationInfo;
        }
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        return null;
    }
}

’ 2)index.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>菜单页面</title>
</head>
<body>
<h1>菜单页面</h1>
<ul>
    <shiro:hasAnyRoles name="admin,user">
        admin、user角色可以看到
        <li>
            <a href="">用户管理</a>
            <shiro:hasPermission name="user:add:*">
                <ul><a href="">增加用户</a></ul>
            </shiro:hasPermission>
            <shiro:hasPermission name="user:delete:*">
                <ul><a href="">删除用户</a></ul>
            </shiro:hasPermission>
            <shiro:hasPermission name="user:update:*">
                <ul><a href="">修改用户</a></ul>
            </shiro:hasPermission>
            <shiro:hasPermission name="user:find:*">
                <ul><a href="">查询用户</a></ul>
            </shiro:hasPermission>
        </li>
    </shiro:hasAnyRoles>
    <li><a href="${pageContext.request.contextPath}/user/logout">退出登陆</a></li>
</ul>
</body>
</html>

’ 3)测试效果:
在这里插入图片描述
9. controller 两种实现:
’ 1)编码式:

@RestController
@RequestMapping(value = "/user")
public class ShiroUserController {

    @RequestMapping(value = "/addUser")
    public String add() {
        Subject subject = SecurityUtils.getSubject();
        if (subject.hasRole("admin")) {
            System.out.println("新增成功");
        } else {
            System.out.println("没有权限");
        }
        return null;
    }

}

’ 2)注解式:

    @RequestMapping(value = "/addUser2")
    @RequiresRoles(value = {"admin"})
    public String add2() {
        System.out.println("新增成功");
        return null;
    }

’ 3)权限字符串形式

    @RequestMapping(value = "/addUser2")
//    @RequiresRoles(value = {"admin"})
    @RequiresPermissions(value = {"user:add:*"})
    public String add2() {
        System.out.println("新增成功");
        return null;
    }

十一:整合 shiro 连接数据库(16~17)

1. 数据库、表结构设计
在这里插入图片描述
在这里插入图片描述
2. 创建数据库:

-- 用户和角色的关系
CREATE TABLE `user_role` (
  `id` bigint(20) unsigned PRIMARY KEY AUTO_INCREMENT,
  `role_id` bigint(20),
  `user_id` bigint(20)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 角色表
CREATE TABLE `role` (
	`id` bigint(20) unsigned PRIMARY KEY AUTO_INCREMENT,
  `name` varchar(128)  default "" COMMENT '名称'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 角色与权限的关系表
CREATE TABLE `role_permission` (
  `id` bigint(20) unsigned PRIMARY KEY AUTO_INCREMENT,
  `role_id` bigint(20),
  `permission_id` bigint(20)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 权限表
CREATE TABLE `permission` (
  `id` bigint(20) unsigned PRIMARY KEY AUTO_INCREMENT,
  `name` varchar(128)  default "" COMMENT '名称',
  `url` varchar(128)  default "" COMMENT '接口路径'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3. 构建用户、角色、权限 实体类:

4. dao 层查询方法:
’ 1)根据用户名查询所有角色:

    <select id="findByUsername" resultType="com.shiro.myshirodemo02jsp.entity.RoleEntity">
        SELECT r.name
        from shiro_user su
                 left join user_role ur on
            su.id = ur.user_id
                 left JOIN `role` r on
            ur.role_id = r.id
        where su.username = #{username}
    </select>

’ 2)业务层实现:

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private ShiroUserService shiroUserService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String primaryPrincipal = (String) principals.getPrimaryPrincipal();
        //根据主体,获取角色信息,权限信息
        List<String> allRoleByUsername = shiroUserService.findAllRoleByUsername(primaryPrincipal);

        if (allRoleByUsername != null) {
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            simpleAuthorizationInfo.addRoles(allRoleByUsername);
            return simpleAuthorizationInfo;
        }
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        return null;
    }
}

6. 查询用户对应的权限字符串,并赋值:
’ 1)根据用户查询角色、根据角色查询对应的权限字符串。
’ 2)在 自定义 Realm 中赋值。

十二:SpringBoot 默认 缓存之 EhCache(21~21)

1. Cache 作用(下)
2. 引入 shiro 与 ehcache 依赖

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.5.3</version>
        </dependency>

3. 在自定义 Realm中,开启缓存管理器

    // 3:创建 realm
    @Bean(value = "realm")
    public Realm realm() {
        CustomerRealm customerRealm = new CustomerRealm();
        // 修改自定义凭证匹配器
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");
        matcher.setHashIterations(1024);
        customerRealm.setCredentialsMatcher(matcher);
        
        // 开启缓存管理器
        customerRealm.setCacheManager(new EhCacheManager());
        customerRealm.setCachingEnabled(true);
        // 设置认证缓存
        customerRealm.setAuthenticationCachingEnabled(true);
        customerRealm.setAuthenticationCacheName("authenticationCacheName");
        // 设置授权缓存
        customerRealm.setAuthorizationCachingEnabled(true);
        customerRealm.setAuthorizationCacheName("authorizationCacheName");
        
        return customerRealm;
    }




十三:SpringBoot 缓存之 Redis:(22~23)

1. 使用 CacheManager;Cache 作用:
在这里插入图片描述
2. 引入依赖:

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

3. yml 配置:

spring:
  redis:
    host: 114.215.173.88
    port: 6379

4. 配置 redis 缓存管理器:
’ 1)开启缓存:

@Configuration
public class ShiroConfig {

    // 3:创建 realm
    @Bean(value = "realm")
    public Realm realm(RedisCacheManager redisCacheManager) {
        CustomerRealm customerRealm = new CustomerRealm();
        // 修改自定义凭证匹配器
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");
        matcher.setHashIterations(1024);
        customerRealm.setCredentialsMatcher(matcher);

        customerRealm.setCacheManager(new RedisCacheManager());
        // 开启全局缓存管理器
        customerRealm.setCachingEnabled(true);
        // 设置认证缓存
        customerRealm.setAuthenticationCachingEnabled(true);
        customerRealm.setAuthenticationCacheName("authenticationCacheName");
        // 设置授权缓存
        customerRealm.setAuthorizationCachingEnabled(true);
        customerRealm.setAuthorizationCacheName("authorizationCacheName");

        return customerRealm;
    }

}

‘ 2)自定义 shiro 缓存管理器:

@Component
public class RedisCacheManager implements CacheManager {

    @Autowired
    private RedisCache redisCache;

    @Override
    public <K, V> Cache<K, V> getCache(String cacheName) throws CacheException {
        System.out.println("cacheName ===" + cacheName);
        return redisCache;
    }

}

在这里插入图片描述
在这里插入图片描述
认证数据加入缓存,user要序列化
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
盐不能序列化,需处理盐
在这里插入图片描述
补其他方法:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

	2、
	3、
	4、
  1. 1

Shiro 整合 thymeleaf

1. 引入 拓展依赖:


        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

2. 页面中 引入命名空间:
在这里插入图片描述
3. 配置文件:
在这里插入图片描述
4.

  1. 2
  2. 2
  3. 2
  4. 2
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值