ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring Boot学习笔记-Spring Boot整合Shiro(二)

2021-07-07 12:34:04  阅读:157  来源: 互联网

标签:return name Spring Boot pwd user id Shiro User


Spring Boot学习

官网:https://spring.io/projects/spring-boot#overview

文档:https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/

参考视频:【狂神说Java】SpringBoot最新教程IDEA版通俗易懂_哔哩哔哩_bilibili

项目完整参考代码:lexiaoyuan/SpringBootStudy: My Spring Boot study notes (github.com)SpringBootStudy: 我的Spring Boot学习笔记 (gitee.com)

Spring Boot学习笔记-Spring Boot整合Shiro(一)

【补充】安装Easy Code插件

介绍:https://gitee.com/makejava/EasyCode

  • 在设置中的插件市场,搜索Easy Code,点击安装,安装完成后重启IDEA即可。(我这里已经安装过了)

在这里插入图片描述

整合MyBatis

  • 首先,打开mysql,确保idea能连接上。

  • pom.xml中导入一些依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.5.2</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.2</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.22</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>
  • 使用Easy Code插件生成代码,按下图操作即可

在这里插入图片描述
在这里插入图片描述

  • 生成代码后的目录,其中UserServiceImpl.java的目录自己做了调整

在这里插入图片描述

  • 配置一下数据源和MyBatis,在resources目录下新建一个application.yml文件
# 配置数据源
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource  # 自定义数据源

    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

# MyBatis配置
mybatis:
  type-aliases-package: com.springboot.entity
  mapper-locations: classpath:mapper/*.xml
  • User.java中增加一个toString方法
/**
 * (User)实体类
 */
public class User{

    private Integer id;
    
    private String name;
    
    private String pwd;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
  • UserDao.java中增加一些代码
/**
 * (User)表数据库访问层
 */
@Repository
@Mapper
public interface UserDao {

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    User queryById(Integer id);

    User queryByName(String name);

    /**
     * 查询指定行数据
     *
     * @param offset 查询起始位置
     * @param limit 查询条数
     * @return 对象列表
     */
    List<User> queryAllByLimit(@Param("offset") int offset, @Param("limit") int limit);


    /**
     * 通过实体作为筛选条件查询
     *
     * @param user 实例对象
     * @return 对象列表
     */
    List<User> queryAll(User user);

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 影响行数
     */
    int insert(User user);

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 影响行数
     */
    int update(User user);

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 影响行数
     */
    int deleteById(Integer id);

}
  • UserService.java中也增加一个queryByName方法
/**
 * (User)表服务接口
 */
public interface UserService {

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    User queryById(Integer id);

    User queryByName(String name);

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit 查询条数
     * @return 对象列表
     */
    List<User> queryAllByLimit(int offset, int limit);

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    User insert(User user);

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    User update(User user);

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    boolean deleteById(Integer id);

}
  • UserServiceImpl.java中也增加一个queryByName方法
/**
 * (User)表服务实现类
 */
@Service("userService")
public class UserServiceImpl implements UserService {
    @Resource
    private UserDao userDao;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public User queryById(Integer id) {
        return this.userDao.queryById(id);
    }

    @Override
    public User queryByName(String name) {
        return this.userDao.queryByName(name);
    }

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit 查询条数
     * @return 对象列表
     */
    @Override
    public List<User> queryAllByLimit(int offset, int limit) {
        return this.userDao.queryAllByLimit(offset, limit);
    }

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User insert(User user) {
        this.userDao.insert(user);
        return user;
    }

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User update(User user) {
        this.userDao.update(user);
        return this.queryById(user.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.userDao.deleteById(id) > 0;
    }
}
  • UserDao.xml中也增加一个queryByName的SQL语句
<?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.springboot.dao.UserDao">

    <resultMap type="com.springboot.entity.User" id="UserMap">
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
        <result property="pwd" column="pwd" jdbcType="VARCHAR"/>
    </resultMap>

    <!--查询单个-->
    <select id="queryById" resultMap="UserMap">
        select
          id, name, pwd
        from mybatis.user
        where id = #{id}
    </select>

    <select id="queryByName" parameterType="String" resultType="user">
        select
          id, name, pwd
        from mybatis.user
        where name = #{name}
    </select>

    <!--查询指定行数据-->
    <select id="queryAllByLimit" resultMap="UserMap">
        select
          id, name, pwd
        from mybatis.user
        limit #{offset}, #{limit}
    </select>

    <!--通过实体作为筛选条件查询-->
    <select id="queryAll" resultMap="UserMap">
        select
          id, name, pwd
        from mybatis.user
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="name != null and name != ''">
                and name = #{name}
            </if>
            <if test="pwd != null and pwd != ''">
                and pwd = #{pwd}
            </if>
        </where>
    </select>

    <!--新增所有列-->
    <insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into mybatis.user(name, pwd)
        values (#{name}, #{pwd})
    </insert>

    <!--通过主键修改数据-->
    <update id="update">
        update mybatis.user
        <set>
            <if test="name != null and name != ''">
                name = #{name},
            </if>
            <if test="pwd != null and pwd != ''">
                pwd = #{pwd},
            </if>
        </set>
        where id = #{id}
    </update>

    <!--通过主键删除-->
    <delete id="deleteById">
        delete from mybatis.user where id = #{id}
    </delete>

</mapper>
  • 首先在测试类里测试一下
@SpringBootTest
class Springboot08ShiroApplicationTests {

    @Autowired
    private UserServiceImpl userService;

    @Test
    void contextLoads() {
        System.out.println(userService.queryById(1).toString());
    }

}
  • 运行测试类,可以看到,没有问题。

在这里插入图片描述

  • 修改UserRealm.java里的认证方法,通过数据库查询用户
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    System.out.println("执行了===》认证doGetAuthorizationInfo");

    UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;

     // 用户名、密码认证,从数据库取
    User user = userService.queryByName(userToken.getUsername());
    
    if (user == null)  // 没有该用户(名)
       return null;  // 会抛出异常 UnknownAccountException

    // 密码认证,shiro做
    // 可以加密:MD5、MD5盐值加密
    return new SimpleAuthenticationInfo("",user.getPwd(),"");
}
  • 再运行web项目,访问:http://localhost:8080/toLogin,输入错误的用户名和密码依然可以提示相关信息,同时,输入数据库中user表中的用户名和密码,则可以登录成功

在这里插入图片描述

  • OK,整合MyBatis和Druid完成!

请求授权

  • ShiroConfig.java中的方法里添加授权规则
// 3. 创建ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    // 设置安全管理器
    shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

    // 添加shiro的内置过滤器
    /**
     * anon: 无需认证就可以访问
     * authc: 必须认证了才能访问
     * user: 必须有记住我功能才能访问
     * perms: 拥有对某个资源的权限才能访问
     * role:拥有某个角色权限才能访问
     */
    // 登录拦截
    Map<String, String> filterMap = new LinkedHashMap<>();

    // 授权 (要放在前面)
    filterMap.put("/user/add", "perms[user:add]");  // 有add权限才能访问add页面
    filterMap.put("/user/update", "perms[user:update]"); // 有update权限才能访问update页面

    // 拦截请求
    filterMap.put("/user/*", "authc");  // 支持通配符

    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

    // 设置登录请求
    shiroFilterFactoryBean.setLoginUrl("/toLogin");

    return shiroFilterFactoryBean;
}
  • 测试:运行一下项目,访问:http://localhost:8080/toLogin,输入正确的用户名和密码(比如:乐小猿,admin)后,登录,再点击add或update链接,发现未授权,

在这里插入图片描述

  • 配置未授权的页面:
  • MyController.java中增加一个方法
@GetMapping("/unauthorized")
@ResponseBody
public String unauthorized() {
    return "没有权限访问该页面";
}
  • 在上面设置登录请求之后再设置未授权的页面
// 设置未授权的页面
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
  • 重复上面的测试,可以看到,进入了自定义的未授权的页面

在这里插入图片描述

  • 给用户添加权限:在UserRealm.java中的授权方法中进行授权
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("执行了===》授权doGetAuthorizationInfo");

    // 进入这个方法就添加权限给用户
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    authorizationInfo.addStringPermission("user:add");

    return authorizationInfo;
}
  • 重复上面的测试,可以看到,登录成功后可以访问add页面

在这里插入图片描述

  • 通过数据库得到当前用户的权限:
  • 首先修改一下user表,增加一列

在这里插入图片描述

  • 然后用Easy Code重新生成一下实体类User.java(自己加了个toString方法)和UserDao.xml(自己加了个queryByName的SQL语句)
/**
 * (User)实体类
 */
public class User implements Serializable {
    private static final long serialVersionUID = 227972241159940478L;
    
    private Integer id;
    
    private String name;
    
    private String pwd;
    
    private String perms;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public String getPerms() {
        return perms;
    }

    public void setPerms(String perms) {
        this.perms = perms;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                ", perms='" + perms + '\'' +
                '}';
    }
}
<?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.springboot.dao.UserDao">

    <resultMap type="com.springboot.entity.User" id="UserMap">
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
        <result property="pwd" column="pwd" jdbcType="VARCHAR"/>
        <result property="perms" column="perms" jdbcType="VARCHAR"/>
    </resultMap>

    <!--查询单个-->
    <select id="queryById" resultMap="UserMap">
        select
          id, name, pwd, perms
        from mybatis.user
        where id = #{id}
    </select>

    <select id="queryByName" parameterType="String" resultType="user">
        select
          id, name, pwd, perms
        from mybatis.user
        where name = #{name}
    </select>

    <!--查询指定行数据-->
    <select id="queryAllByLimit" resultMap="UserMap">
        select
          id, name, pwd, perms
        from mybatis.user
        limit #{offset}, #{limit}
    </select>

    <!--通过实体作为筛选条件查询-->
    <select id="queryAll" resultMap="UserMap">
        select
          id, name, pwd, perms
        from mybatis.user
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="name != null and name != ''">
                and name = #{name}
            </if>
            <if test="pwd != null and pwd != ''">
                and pwd = #{pwd}
            </if>
            <if test="perms != null and perms != ''">
                and perms = #{perms}
            </if>
        </where>
    </select>

    <!--新增所有列-->
    <insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into mybatis.user(name, pwd, perms)
        values (#{name}, #{pwd}, #{perms})
    </insert>

    <!--通过主键修改数据-->
    <update id="update">
        update mybatis.user
        <set>
            <if test="name != null and name != ''">
                name = #{name},
            </if>
            <if test="pwd != null and pwd != ''">
                pwd = #{pwd},
            </if>
            <if test="perms != null and perms != ''">
                perms = #{perms},
            </if>
        </set>
        where id = #{id}
    </update>

    <!--通过主键删除-->
    <delete id="deleteById">
        delete from mybatis.user where id = #{id}
    </delete>

</mapper>
  • 修改一下UserRealm.java中的认证和授权的方法
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("执行了===》授权doGetAuthorizationInfo");

    // 进入这个方法就添加权限给用户
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    //authorizationInfo.addStringPermission("user:add");

    // 拿到当前的对象
    Subject subject = SecurityUtils.getSubject();
    User currentUser = (User) subject.getPrincipal();  // 拿到下面认证方法中传上来的user对象

    // 添加当前用户的权限,通过数据库得到当前用户的权限
    authorizationInfo.addStringPermission(currentUser.getPerms());

    return authorizationInfo;
}

// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    System.out.println("执行了===》认证doGetAuthorizationInfo");

    UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
    
    // 用户名、密码认证,从数据库取  
    User user = userService.queryByName(userToken.getUsername());

    if (user == null)  // 没有该用户(名)
       return null;  // 会抛出异常 UnknownAccountException
    
    // 把从数据库中查到的user传递到上面授权的方法
    return new SimpleAuthenticationInfo(user,user.getPwd(),"");
}
  • 测试:访问:http://localhost:8080/toLogin,使用数据库中user表中的用户名和密码登录,可以看到,只有个拥有一定权限的用户才能访问其能访问的页面。测试OK!
  • 请求授权完成!

shiro整合thymeleaf

官网文档:https://github.com/theborakompanioni/thymeleaf-extras-shiro

  • pom.xml中添加整合依赖
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>
  • ShiroConfig.java中整合shiro和thymeleaf
// 整合ShiroDialect:用来整合shiro和thymeleaf
@Bean
public ShiroDialect getShiroDialect(){
    return new ShiroDialect();
}
  • index.html中添加判断
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>首页</h1>
  <p th:text="${msg}"></p>

  <p shiro:notAuthenticated="">
    <a th:href="@{/toLogin}">登录</a>
  </p>

  <div shiro:hasPermission="user:add">
    <a th:href="@{/user/add}">add</a>
  </div>

  <div shiro:hasPermission="user:update">
    <a th:href="@{/user/update}">update</a>
  </div>

</body>
</html>
  • 重新运行项目,访问:http://localhost:8080/,没有登录时只显示登录

在这里插入图片描述

  • 点击登录,用乐小猿的账户登录,只有add权限,就只显示add页面

在这里插入图片描述

在这里插入图片描述

  • 用beta的账户登录,只有update权限,就只显示update页面

在这里插入图片描述

在这里插入图片描述

  • OK,整合完成!

标签:return,name,Spring,Boot,pwd,user,id,Shiro,User
来源: https://blog.csdn.net/xu_benjamin/article/details/118520651

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有