栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot基础学习之整合Shiro框架(下篇)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot基础学习之整合Shiro框架(下篇)

前言:

小伙伴们,大家好,我是狂奔の蜗牛rz,当然你们可以叫我蜗牛君,我是一个学习Java半年多时间的小菜鸟,同时还有一个伟大的梦想,那就是有朝一日,成为一个优秀的Java架构师。


这个SpringBoot基础学习系列用来记录我学习SpringBoot框架基础知识的全过程 (这个系列是参照B站狂神的SpringBoot最新教程来写的,由于是之前整理的,但当时没有发布出来,所以有些地方可能有错误,希望大家能够及时指正!)

之后我将会尽量以一天一更的速度更新这个系列,还没有学习SpringBoot的小伙伴可以参照我的博客学习一下;当然学习过的小伙伴,也可以顺便跟我一起复习一下基础。最后,希望能够和大家一同进步吧!加油吧!少年们!


由于篇幅较长,所以这里我将其分为了上下两篇博客,上篇主要了解Shiro的功能,以及基本环境的搭建;下篇主要学习Shiro整合Mybatis和Thymeleaf框架

特别提醒: 上篇博客链接:SpringBoot基础学习之整合Shiro框架(上篇)

今天我们来到了SpringBoot基础学习的第九站:整合Shiro框架(下篇)。废话不多说,让我们开始今天的学习内容吧!

8.4 Shiro整合Mybatis 8.4.1 导入模块相关资源依赖 1.导入MySQL数据库驱动资源依赖

    mysql
    mysql-connector-java
    runtime
    5.1.46

2.导入mybatis整合springboot资源依赖


    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    2.1.3

3.导入Druid数据源资源依赖


    com.alibaba
    druid
    1.1.12

4.导入lombok的资源依赖

    org.projectlombok
    lombok
    1.16.10

5.所有的资源依赖

    
    
    
    
        org.apache.shiro
        shiro-spring
        1.4.1
    
    
    
        org.springframework.boot
        spring-boot-starter-thymeleaf
    
    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    
    
    
    
        log4j
        log4j
        1.2.17
    
    
    
        mysql
        mysql-connector-java
        runtime
        5.1.46
    
    
    
    
    
    
        org.mybatis.spring.boot
        mybatis-spring-boot-starter
        2.1.3
    
    
    
    
        com.alibaba
        druid
        1.1.12
    
    
    
        org.projectlombok
        lombok
        1.16.10
    
    

8.4.2 搭建项目基本环境 1.项目模块基本结构和编写配置文件 1-1 项目模块基本结构

1-2 编写application.yml配置文件
# 设置服务器端口号
server:
  port: 8888

# 设置数据库驱动
spring:
  datasource:
    username: root
    password: 123456
    # 8.0以下版本的url连接格式
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true
    # 8.0以下版本的数据库驱动
    driver-class-name: com.mysql.jdbc.Driver

    # 使用Druid的数据源
    type: com.alibaba.druid.pool.DruidDataSource
    # Spring Boot 默认是不注入这些属性值的,因此需要自己来配置
    # 设置Druid数据源的基本配置
    # 初始化时的物理连接个数:初始化发生在显式调用init方法或者第一次getConnection时
    initialSize: 5
    # 最小连接池数量
    minIdle: 5
    # 最大连接池数量
    maxActive: 20
    # 获取连接的最大等待时间,时间单位是毫秒
    maxWait: 60000
    # 运行和回收的间隔时间:即销毁线程检测连接的间隔时间
    timeBetweenEvictionRunsMillis: 300000
    # 最小回收时间:如果检测到当前连接的最后活跃时间和当前时间大于最小回收时间,则关闭当前连接
    minEvictableIdleTimeMillis: 300000
    # 判断连接到的查询语句是否有效
    validationQuery: Select 1 from dual
    # 检测空闲连接时间:建议设置为true,申请连接检测,如果空闲时间大于回收运行间隔时间,执行检测连接到的查询语句是否生效
    testWhiteIdle: true
    # 检测引入的查询语言的连接是否生效:此配置会降低性能,默认值为false
    testOnBorrow: false
    # 检测归还连接时执行生效查询语句是否有效:此配置会降低性能
    testOnReturn: false
    # 是否缓存预编译语句池:即使用PSCache,默认值为false,MySQL5.5以上版本有PSCache,建议开启
    poolPreparedStatements: true

    # 配置监控拦截的filters:监控统计-stat;日志记录-log4j;防御SQL注入:wall
    # 如果运行时报错-java.lang.ClassNotFoundException:org.apache,log4j.Priority
    # 则导入log4j依赖即可,Maven仓库地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,log4j,wall
    # 设置每个连接的最大池预编译语句大小
    maxPoolPreparedStatementPerConnectionSize: 20
    # 设置使用全局的数据源的监控统计拦截器stat
    useGlobalDataSourceStat: true
    # 设置连接属性:监控统计拦截器stat的mergeSql(合并SQL)属性为true,即此配置生效;慢SQL时间为0.5秒
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

# 配置mybatis相关属性
mybatis:
  # 通过包设置别名
  type-aliases-package: com.kuang.pojo
  # 设置mapper映射文件的位置
  mapper-locations: classpath:mapper/*.xml
2.编写User实体类和UserMapper接口及映射文件 2-1 编写User实体类
package com.kuang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

@Data // 导入无参构造, set和get方法, 以及toString方法
@AllArgsConstructor // 导入有参构造
@NoArgsConstructor // 再次无参构造,防止无参构造被覆盖掉
// 实现Serializable接口,序列化User对象
public class User implements Serializable {
    
    private Integer id; // 编号
    private String name; // 用户名
    private String pwd; // 密码
    
}
2-2 编写UserMapper接口
package com.kuang.mapper;

import com.kuang.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Repository // 将Dao层交由Spring的IOC容器统一管理
@Mapper // 注册为Mapper接口
public interface UserMapper {
    
    // 通过用户名获取指定用户信息
    public User getUserByName(String name);
    
}
2-3 编写UserMapper.xml映射文件




    
    
        Select id, name, pwd from mybatis.user where name = #{name}
    


3.编写UserService接口和UserServiceImpl实现类 3-1 编写UserService接口
package com.kuang.service;

import com.kuang.pojo.User;

public interface UserService {
    
    // 通过用户名获取指定用户信息
    public User getUserByName(String name);
    
}
3-2 编写UserServiceImpl实现类
package com.kuang.service.impl;

import com.kuang.mapper.UserMapper;
import com.kuang.pojo.User;
import com.kuang.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

// 将Service层交由Spring的IOC容器统一管理
@Service
public class UserServiceImpl implements UserService {
    
    // 自动注入UserMapper接口
    @Autowired
    private UserMapper userMapper;

    // 根据用户名获取指定用户信息
    @Override
    public User getUserByName(String name) {
        return this.userMapper.getUserByName(name);
    }
    
}
4.修改UserRealm配置类和编写UserController控制类 4-1 修改UserRealm配置类
package com.kuang.config;

import com.kuang.pojo.User;
import com.kuang.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import sun.security.provider.MD5;

// 自定义UserRealm,继承AuthorizingRealm类
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权doGetAuthorizationInfo");
        // 1.1 获取简单授权信息(SimpleAuthorizationInfo)对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        
        // 1.2 在授权认证信息(authorizationInfo)中设置权限请求的值
//        authorizationInfo.addStringPermission("user:addUser");
        // 1.3 获取当前登录的这个用户(即subject对象)
        Subject subject = SecurityUtils.getSubject();
        // 1.4 获取当前用户的权限
        User currentUser = (User) subject.getPrincipal();
        // 1.5 设置当前用户的权限,存入到授权认证信息(authorizationInfo)中去
        authorizationInfo.addStringPermission(currentUser.getPerms());
        // 1.6 获取当前用户的权限
        String perms = currentUser.getPerms();
        // 1.7 判断当前用户的权限是否为空
        if(perms!=null) {
            // 1.7.1 设置当前用户的权限,存入到授权认证信息(authorizationInfo)中去
            authorizationInfo.addStringPermission(currentUser.getPerms());
            // 1.7.2 将授权后的认证信息进行返回
            return authorizationInfo;
        } else {
            // 1.7.3 如果用户的权限为空,返回null值,抛出异常
            return null;
       }
    }

    
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        
        System.out.println("执行了=>授权doGetAuthenticationInfo");
        
        
        // 2.2.1 获取用户认证信息:可以打断点做测试
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
        // 2.2.2 通过用户名获取来获取用户信息
        User user = userService.getUserByName(userToken.getUsername());
        // 2.2.3 判断用户信息是否为空
        if(user==null) {
          // 如果用户名不存在,就抛出异常UnknownAccountException
          return null;
        }
        
        
       return new SimpleAuthenticationInfo("",user.getPwd(),"");
    }
    
}
4-2 编写UserController接口
package com.kuang.controller;

import com.kuang.pojo.User;
import com.kuang.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

@Controller
public class UserController {
    
    
    @RequestMapping({"/","/index"})
    public String toIndex(Model model) {
        // 设置视图模型信息
        model.addAttribute("msg", "Hello,Shiro!");
        // 返回视图逻辑名
        return "index";
    }

    
    @RequestMapping("/user/addUser")
    public String toAddPage() {
        // 返回视图逻辑名
        return "user/addUser";
    }

    
    @RequestMapping("/user/updateUser")
    public String toUpdatePage() {
        // 返回视图逻辑名
        return "user/updateUser";
    }

    
    
    @RequestMapping("/toLogin")
    public String toLogin() {
        // 返回视图逻辑名
        return "login";
    }
    
    
    @PostMapping("/login")
    public String login(String username, String password,Model model) {
        // 获取当前用户
        Subject subject = SecurityUtils.getSubject();
        // 封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username,MD5Util.MD5EncodeUtf8(password));
        try{
            // 执行登录方法,如果没有异常就说明OK了
            subject.login(token);
            // 设置视图逻辑名为index主页
            return "index";
        // 捕获未知用户异常
        } catch(UnknownAccountException uae) {
            // 设置视图模型信息
            model.addAttribute("msg","用户名错误");
            // 设置视图逻辑名为login登录页
            return "login";
        // 捕获错误认证异常
        } catch (IncorrectCredentialsException ica) {
            // 设置视图模型信息
            model.addAttribute("msg","密码错误");
            // 设置视图逻辑名为login登录页
            return "login";
        }
    }

}
5.编写测试类和测试结果 5-1 编写ShiroSpringbootApplicationTests测试类
package com.kuang;

import com.kuang.service.impl.UserServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ShiroSpringbootApplicationTests {

    @Autowired
    private UserServiceImpl userService;

    @Test
    void contextLoads() {
        // 打印通过用户名获取的用户信息
        System.out.println(userService.getUserByName("root"));
    }

}
5-2 测试结果

结果:控制台中成功输出6号用户的账号密码信息!

8.4.3 完善项目环境 1.修改UserRealm和ShiroConfig配置类 1-1 修改UserRealm配置类
package com.kuang.config;

import com.kuang.pojo.User;
import com.kuang.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import sun.security.provider.MD5;

// 自定义UserRealm,继承AuthorizingRealm类
public class UserRealm extends AuthorizingRealm {

    // 使用@Autowired注解, 通过类型自动装配UserService接口
    @Autowired
    private UserService userService;

    
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        
        System.out.println("执行了=>授权doGetAuthorizationInfo");
        // 1.1 获取简单授权信息(SimpleAuthorizationInfo)对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 1.2 在授权认证信息(authorizationInfo)中设置权限请 求的值
//        authorizationInfo.addStringPermission("user:addUser");
        // 1.3 获取当前登录的这个用户(即subject对象)
        Subject subject = SecurityUtils.getSubject();
        // 1.4 获取当前用户的权限
        User currentUser = (User) subject.getPrincipal();
        // 1.5 设置当前用户的权限,存入到授权认证信息(authorizationInfo)中去
        authorizationInfo.addStringPermission(currentUser.getPerms());
        // 1.6 获取当前用户的权限
        String perms = currentUser.getPerms();
        // 1.7 判断当前用户的权限是否为空
        if(perms!=null) {
            // 1.7.1 设置当前用户的权限,存入到授权认证信息(authorizationInfo)中去
            authorizationInfo.addStringPermission(currentUser.getPerms());
            // 1.7.2 将授权后的认证信息进行返回
            return authorizationInfo;
        } else {
            // 1.7.3 如果用户的权限为空,返回null值,抛出异常
            return null;
       }
        
    }

    
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        
        System.out.println("执行了=>授权doGetAuthenticationInfo");
        
        // 2.2.1 获取用户认证信息:可以打断点做测试
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
        // 2.2.2 通过用户名获取来获取用户信息
        User user = userService.getUserByName(userToken.getUsername());
        // 2.2.3 判断用户信息是否为空
        if(user==null) {
          // 如果用户名不存在,就抛出异常UnknownAccountException
          return null;
        }

        
        
        // 2.3.2 在principal参数中,把user传进来;密码加密使用盐值加密
        return new SimpleAuthenticationInfo(user, MD5Util.MD5EncodeUtf8(user.getPwd()),"");
    }
    
}
1-2 修改ShiroConfig配置类
package com.kuang.config;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.linkedHashMap;
import java.util.Map;

// 使用@Configuration注解, 让ShiroConfig成为配置类
@Configuration
public class ShiroConfig {
    
    
    // 1.1 将userRealm作为组件, 注册到Spring的IOC容器中去
    @Bean
    public UserRealm userRealm() {
        // 1.2 返回值为创建一个UserRealm对象
        return new UserRealm();
    }

    
    // 2.1 使用@Bean注解,将getDefaultWebSecurityManager方法作为作为组件, 注册到Spring的IOC容器中去
    @Bean(name="securityManager")
    // 2.2 使用@Qualifier注解,通过名字userRealm获取SpringdeIOC容器中的UserRealm对象
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        // 2.3 获取DefaultWebSecurityManager对象
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        // 2.4 关联userRealm对象
        securityManager.setRealm(userRealm);
        // 2.5 返回securityManager对象
        return securityManager;
    }
    
    
    // 使用@Bean注解,将getShiroFilterFactoryBean方法注册到Spring容器中去
    @Bean
    // 使用@Qualifier注解,通过名字securityManage获取Spring容器中的DefaultWebSecurityManager对象
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        // 3.1 获取Shiro的过滤工厂, 设置安全管理器
        // 3.1.1 获取ShiroFilterFactoryBean对象
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        // 3.1.2 设置securityManager(安全管理器)对象
        factoryBean.setSecurityManager(securityManager);

        
        
        // 获取linkedHashMap对象
        Map filterMap = new linkedHashMap<>();

         
       // #1 "/user/addUser"是添加用户的请求,"perms[user:addUser]"表示只有拥有添加用户权限才能访问
         filterMap.put("/user/addUser", "perms[user:addUser]");
        // #2 "/user/updateUser"是修改用户的请求,"perms[user:updateUser]"表示只有拥有修改用户权限才能访问
        filterMap.put("/user/updateUser", "perms[user:updateUser]");
        // #3 "/user
        // 3.3.1 设置登录的请求
        factoryBean.setLoginUrl("/toLogin");
        // 3.3.2 未授权页面的请求
        factoryBean.setUnauthorizedUrl("/unAuthorized");

        // 3.4 返回factoryBean对象
        return factoryBean;
    }
    
}
2.修改UserController控制类
package com.kuang.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.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {

    
    @RequestMapping({"/","/index"})
    public String toIndex(Model model) {
        // 设置视图模型信息
        model.addAttribute("msg", "Hello,Shiro!");
        // 返回视图逻辑名
        return "index";
    }

    
    @RequestMapping("/user/addUser")
    public String toAddPage() {
        // 返回视图逻辑名
        return "user/addUser";
    }

    
    @RequestMapping("/user/updateUser")
    public String toUpdatePage() {
        // 返回视图逻辑名
        return "user/updateUser";
    }

    
    
    @RequestMapping("/toLogin")
    public String toLogin() {
        // 返回视图逻辑名
        return "login";
    }
    
    
    @PostMapping("/login")
    public String login(String username, String password,Model model) {
        // 获取当前用户
        Subject subject = SecurityUtils.getSubject();
        // 封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username,MD5Util.MD5EncodeUtf8(password));
        try{
            // 执行登录方法,如果没有异常就说明OK了
            subject.login(token);
            // 设置视图逻辑名为index主页
            return "index";
        // 捕获未知用户异常
        } catch(UnknownAccountException uae) {
            // 设置视图模型信息
            model.addAttribute("msg","用户名错误");
            // 设置视图逻辑名为login登录页
            return "login";
        // 捕获错误认证异常
        } catch (IncorrectCredentialsException ica) {
            // 设置视图模型信息
            model.addAttribute("msg","密码错误");
            // 设置视图逻辑名为login登录页
            return "login";
        }
    }

    
    @RequestMapping("/unAuthorized")
    // 使用@ResponseBody注解, 将方法返回的字符串转化为JSON串
    @ResponseBody 
    public String unAuthorized() {
        return "未授权,无法访问此页面!";
    }

}
3. 修改User实体类和编写MD5工具类 3-1 修改User实体类
package com.kuang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data // 导入无参构造, set和get方法, 以及toString方法
@AllArgsConstructor // 导入有参构造
@NoArgsConstructor // 再次无参构造,防止无参构造被覆盖掉
// 实现Serializable接口,序列化User对象
public class User implements Serializable {
    
    private Integer id; //编号
    private String name; //用户名
    private String pwd; //密码
    private String perms; //权限
    
}

3-2 编写MD5Util工具类
package com.kuang.utils;

import java.security.MessageDigest;

public class MD5Util {

    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    
    private static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString.toUpperCase();
    }

    public static String MD5EncodeUtf8(String origin) {

        //盐值Salt加密
        //origin = origin + PropertiesUtil.getProperty("password.salt", "");
        return MD5Encode(origin, "utf-8");
    }


    private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

}
4.修改数据库信息 4-1 修改User表
  • 添加varchar类型perms字段,用来设置用户的权限
4-2 给用户添加权限

4.权限验证测试 4-1 使用root账户登录
  • 登录root用户进行测试

  • 访问添加用户页面

  • 访问修改用户页面

4-2 使用admin账户登录
  • 登录admin用户进行测试

  • 访问新增用户页面

  • 访问修改用户页面

8.5 Shiro整合thymeleaf 8.5.1 导入资源依赖和修改部分代码 1.导入shiro整合thymeleaf资源依赖


    com.github.theborakompanioni
    thymeleaf-extras-shiro
    2.0.0

2.修改ShiroConfig配置类
package com.kuang.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.linkedHashMap;
import java.util.Map;

// 使用@Configuration注解, 让ShiroConfig成为配置类
@Configuration
public class ShiroConfig {

    
    // 1.1 将userRealm作为组件, 注册到Spring的IOC容器中去
    @Bean
    public UserRealm userRealm() {
        // 1.2 返回值为创建一个UserRealm对象
        return new UserRealm();
    }

    
    // 2.1 使用@Bean注解,将getDefaultWebSecurityManager方法作为作为组件, 注册到Spring的IOC容器中去
    @Bean(name="securityManager")
    // 2.2 使用@Qualifier注解,通过名字userRealm获取SpringdeIOC容器中的UserRealm对象
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        // 2.3 获取DefaultWebSecurityManager对象
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        // 2.4 关联userRealm对象
        securityManager.setRealm(userRealm);
        // 2.5 返回securityManager对象
        return securityManager;
    }
    
    
    // 使用@Bean注解,将getShiroFilterFactoryBean方法注册到Spring容器中去
    @Bean
    // 使用@Qualifier注解,通过名字securityManage获取Spring容器中的DefaultWebSecurityManager对象
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        // 3.1 获取Shiro的过滤工厂, 设置安全管理器
        // 3.1.1 获取ShiroFilterFactoryBean对象
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        // 3.1.2 设置securityManager(安全管理器)对象
        factoryBean.setSecurityManager(securityManager);

        
        
        // 获取linkedHashMap对象
        Map filterMap = new linkedHashMap<>();

         
       // #1 "/user/addUser"是添加用户的请求,"perms[user:addUser]"表示只有拥有添加用户权限才能访问
         filterMap.put("/user/addUser", "perms[user:addUser]");
        // #2 "/user/updateUser"是修改用户的请求,"perms[user:updateUser]"表示只有拥有修改用户权限才能访问
        filterMap.put("/user/updateUser", "perms[user:updateUser]");
        // #3 "/user
        // 3.3.1 设置登录的请求
        factoryBean.setLoginUrl("/toLogin");
        // 3.3.2 未授权页面的请求
        factoryBean.setUnauthorizedUrl("/unAuthorized");

        // 3.4 返回factoryBean对象
        return factoryBean;
    }

    
    // 4.1 将ShiroDialect注册到Spring容器中去
    @Bean
    public ShiroDialect getShiroDialect() {
        // 4.2 将ShiroDialect对象进行返回
        return new ShiroDialect();
    }

}
3.修改UserRealm配置类
package com.kuang.config;

import com.kuang.pojo.User;
import com.kuang.service.UserService;
import com.kuang.utils.MD5Util;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

// 自定义UserRealm, 继承AuthorizingRealm类
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        
        System.out.println("执行了=>授权doGetAuthorizationInfo");
        
        // 1.1 获取简单授权信息(SimpleAuthorizationInfo)对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 1.3 获取当前登录的这个用户(即subject对象)
        Subject subject = SecurityUtils.getSubject();
        // 1.4 获取当前用户的权限
        User currentUser = (User) subject.getPrincipal();
        // 1.5 设置当前用户的权限,存入到授权认证信息(authorizationInfo)中去
        authorizationInfo.addStringPermission(currentUser.getPerms());
        // 1.6 获取当前用户的权限
        String perms = currentUser.getPerms();
        // 1.7 判断当前用户的权限是否为空
        if(perms!=null) {
            // 1.7.1 设置当前用户的权限,存入到授权认证信息(authorizationInfo)中去
            authorizationInfo.addStringPermission(currentUser.getPerms());
            // 1.7.2 将授权后的认证信息进行返回
            return authorizationInfo;
        } else {
            // 1.7.3 如果用户的权限为空,返回null值,抛出异常
            return null;
       }
    }

    
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        
        System.out.println("执行了=>授权doGetAuthenticationInfo");
        
        
        // 2.2.1 获取用户认证信息:可以打断点做测试
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
        // 2.2.2 通过用户名获取来获取用户信息
        User user = userService.getUserByName(userToken.getUsername());
        // 2.2.3 判断用户信息是否为空
        if(user==null) {
          // 如果用户名不存在,就抛出异常UnknownAccountException
          return null;
        }
        
        
        // 3.1 获取当前用户
        Subject currentUser = SecurityUtils.getSubject();
        // 3.2 获取当前用户的session信息
        Session userSession = currentUser.getSession();
        // 3.3 设置当前用户的session信息,将用户名封装到loginUser中去
        userSession.setAttribute("loginUser",user.getName());

        
        
        // 2.4.2 在principal参数中,把user传进来;密码加密使用盐值加密
        return new SimpleAuthenticationInfo(user, user.getPwd(),"");
    }
    
}
4.修改UserController控制类
package com.kuang.controller;

import com.kuang.utils.MD5Util;
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.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {

    
    @RequestMapping({"/","/index"})
    public String toIndex(Model model) {
        // 设置视图模型信息
        model.addAttribute("msg", "Hello,Shiro!");
        // 返回视图逻辑名
        return "index";
    }

    
    @RequestMapping("/user/addUser")
    public String toAddPage() {
        // 返回视图逻辑名
        return "user/addUser";
    }

    
    @RequestMapping("/user/updateUser")
    public String toUpdatePage() {
        // 返回视图逻辑名
        return "user/updateUser";
    }

    
    
    @RequestMapping("/toLogin")
    public String toLogin() {
        // 返回视图逻辑名
        return "login";
    }
    
    
    @PostMapping("/login")
    public String login(String username, String password,Model model) {
        // 获取当前用户
        Subject subject = SecurityUtils.getSubject();
        // 封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username,MD5Util.MD5EncodeUtf8(password));
        try{
            // 执行登录方法,如果没有异常就说明OK了
            subject.login(token);
            // 设置视图逻辑名为index主页
            return "index";
        // 捕获未知用户异常
        } catch(UnknownAccountException uae) {
            // 设置视图模型信息
            model.addAttribute("msg","用户名错误");
            // 设置视图逻辑名为login登录页
            return "login";
        // 捕获错误认证异常
        } catch (IncorrectCredentialsException ica) {
            // 设置视图模型信息
            model.addAttribute("msg","密码错误");
            // 设置视图逻辑名为login登录页
            return "login";
        }
    }

    
    @RequestMapping("/unAuthorized")
    // 使用@ResponseBody注解, 将方法返回的字符串转化为JSON串
    @ResponseBody 
    public String unAuthorized() {
        return "未授权,无法访问此页面!";
    }

    
    @RequestMapping("/logout")
    public String logout(){
        // 获取当前用户信息
        Subject currentUser = SecurityUtils.getSubject();
        // 注销当前登录用户
        currentUser.logout();
        // 返回到index主页
        return "index";
    }
    
}
8.5.2 修改页面和登录验证测试 1.修改login.html登录页




    
    登录


登录


用户名:

密码:

记住我

2.修改index.html主页




    
    首页


首页


3.登录验证测试 3-1 使用root账户登录
  • 未登录

  • 登录root账户

  • 访问首页成功

  • 访问修改用户页面

  • 退出登录

3-2 使用admin账户登录
  • 登录root账户

  • 访问首页成功

  • 访问新增用户页面


好了,今天的有关 SpringBoot基础学习之整合Shiro框架(下篇) 的学习就到此结束啦,欢迎小伙伴们积极学习和讨论,喜欢的可以给蜗牛君点个关注,顺便来个一键三连,我们下期见,拜拜啦!


参考视频链接:https://www.bilibili.com/video/BV1PE411i7CV(【狂神说Java】SpringBoot最新教程IDEA版通俗易懂)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/349224.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号