springboot整合shiro入门项目

整个项目结构:

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

1、引入依赖

开发环境:IDEA、mysql8.0、maven、mybatis、shiro、thymeleaf

首先搭建一个springboot项目,接着引入依赖,本项目中所有依赖均在此pom.xml文件中

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.shiro.test</groupId>
    <artifactId>shiro</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shiro</name>
    <description>Shiro project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--        thymeleaf模板依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!--引入thymeleaf-shiro依赖-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

        <!--        shiro-springboot依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.8.0</version>
        </dependency>

        <!--        mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--        打印日志依赖包-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!--        数据库连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
        </dependency>

        <!--        整合mybatis和springboot-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.1.0</version>
            </plugin>
        </plugins>
    </build>

</project>


2、新增shiro配置类

与shiro相关的配置类,共有两个,分别是ShiroConfig.java和UserRealm.java

  • ShiroConfig.java
package com.shiro.test.shiro.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;

/**
 * @Description
 * @ClassName ShiroConfig
 * @Author yuhuofei
 * @Date 2021/11/21 12:32
 * @Version 1.0
 */
@Configuration
public class ShiroConfig {

    //ShiroFilterFactoryBean(第三步)
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("manager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();

        //关联到DefaultWebSecurityManager,设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);

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

        //权限拦截,拥有授权字符串user:add,才能访问/user/add
        filterMap.put("/user/add","perms[user:add]");
        //权限拦截,拥有授权字符串user:update,才能访问/user/update
        filterMap.put("/user/update","perms[user:update]");

        //拦截/user/目录下所有,必须认证才能访问
        //filterMap.put("/user/add","authc");
        //filterMap.put("/user/update","authc");
        filterMap.put("/user/*","authc");

        //设置过滤器的过滤链
        bean.setFilterChainDefinitionMap(filterMap);

        //拦截后,设置跳转的请求(加/表示绝对路径,不加/表示相对路径)
        bean.setLoginUrl("/toLogin");

        //未经授权的跳转
        bean.setUnauthorizedUrl("/unAuth");

        return bean;
    }

    //DefaultWebSecurityManager(第二步)
    @Bean(name = "manager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("realm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        //关联UserRealm,进行管理
        securityManager.setRealm(userRealm);

        return securityManager;
    }

    //创建realm对象,需要自定义一个类实现,本文是自定义了UserRealm类(第一步)
    @Bean(name = "realm")
    public UserRealm getUserRealm() {
        return new UserRealm();
    }

    //整合shiro thymeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
}


  • UserRealm.java
package com.shiro.test.shiro.config;

import com.shiro.test.shiro.entity.User;
import com.shiro.test.shiro.service.UserService;
import lombok.extern.slf4j.Slf4j;
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;

/**
 * @Description 自定义的realm,继承AuthorizingRealm,重写两个方法
 * @ClassName UserRealm
 * @Author yuhuofei
 * @Date 2021/11/21 12:36
 * @Version 1.0
 */
@Slf4j
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    //授权方法,用于授权用户访问指定资源的权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("授权方法被执行成功!");
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        //获取当前登录的这个用户对象
        Subject subject = SecurityUtils.getSubject();
        User curUser = (User) subject.getPrincipal();

        //获取数据库中配置的权限,为当前用户进行授权
        simpleAuthorizationInfo.addStringPermission(curUser.getPerms());
        log.info("当前用户拥有的权限"+curUser.getPerms());

        return simpleAuthorizationInfo;
    }

    //认证方法,用于登录时,认证该登录用户是否可以登录
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("认证方法被执行成功!");


        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;

        //从数据库中查记录
        User user = userService.queryByUserName(userToken.getUsername());

        if (user == null) {//无此用户
            return null;
        }

        //此处可以对密码进行MD5盐值加密
        //密码认证
        return new SimpleAuthenticationInfo(user,user.getPassWord(),"");

    }
}

3、 新增html页面

共4个页面,分别是login.html、index.html、add.html、update.html

  • login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<h1>登录</h1>
<hr>
<p th:text="${msg}" style="color: red"></p>
<form th:action="@{/login}">
    <p>用户名: <input type="text" name="userName"></p>
    <p>密码: <input type="text" name="passWord"></p>
    <p><input type="submit"></p>
</form>

</body>
</html>
  • index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>首页</h1>
<p th:text="${msg}"></p>
<hr>

<!--有user:add权限才展示新增菜单-->
<shiro:hasPermission name="user:add">
    <a th:href="@{/user/add}">新增</a>
</shiro:hasPermission>

<!--有user:update权限才展示修改菜单-->
<shiro:hasPermission name="user:update">
    <a th:href="@{/user/update}">修改</a>
</shiro:hasPermission>

<a th:href="@{/logout}">退出</a>

</body>
</html>
  • add.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加用户</title>
</head>
<body>
<h1>add</h1>
</body>
</html>
  • update.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改用户</title>
</head>
<body>
<h1>update</h1>
</body>
</html>

4、新建数据库表,整合mysql、mybatis、springboot

4.1 新建数据库表
# 新建一个数据库
CREATE DATABASE `shiro_test`;

# 使用数据库
USE `shiro_test`;

# 创建用户表
CREATE TABLE `user`(
	`user_id` INT(20) PRIMARY KEY,
	`user_name` VARCHAR(30) DEFAULT NULL,
	`password` VARCHAR(30) DEFAULT NULL,
	`perms` VARCHAR(100) DEFAULT NULL
)ENGINE INNODB CHARACTER SET utf8 COLLATE utf8_bin;
4.2 整合mysql、mybatis、springboot
  • 引入依赖
    在前面的pom.xml中,已经引入,可以参考前面的pom.xml文件
  • 在配置文件application.properties中新增以下内容
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro_test?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
spring.datasource.username=root
spring.datasource.password=pan
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

mybatis.type-aliases-package=com.shiro.test.shiro.entity
mybatis.mapper-locations=classpath:mapper/*.xml
#开启驼峰字段映射
mybatis.configuration.map-underscore-to-camel-case=true
  • 新建实体类,User.java
package com.shiro.test.shiro.entity;

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

/**
 * @Description 实体类
 * @ClassName User
 * @Author yuhuofei
 * @Date 2021/11/21 18:53
 * @Version 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private Integer userId;

    private String userName;

    private String passWord;

    private String perms;
}

  • 新建mapper层接口,UserMapper
package com.shiro.test.shiro.mapper;

import com.shiro.test.shiro.entity.User;
import org.apache.ibatis.annotations.Mapper;

/**
 * @Description
 * @InterfaceName UserMapper
 * @Author yuhuofei
 * @Date 2021/11/21 18:57
 * @Version 1.0
 */
@Mapper
public interface UserMapper {

    User queryByUserName(String userName);
}

  • 新建UserMapper.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.test.shiro.mapper.UserMapper">
    <resultMap id="userResultMap" type="com.shiro.test.shiro.entity.User">
        <result column="user_id" property="userId"/>
        <result column="user_name" property="userName"/>
        <result column="password" property="passWord"/>
        <result column="perms" property="perms"/>
    </resultMap>

    <sql id="Base_Column_List">
        user_id,user_name,password,perms
  </sql>

    <select id="queryByUserName" parameterType="String" resultType="com.shiro.test.shiro.entity.User">
        select user_id,user_name,password,perms
        from shiro_test.user
        where user_name = #{userName}
    </select>

</mapper>
  • 新建service层接口
package com.shiro.test.shiro.service;

import com.shiro.test.shiro.entity.User;

/**
 * @Description
 * @InterfaceName UserService
 * @Author yuhuofei
 * @Date 2021/11/21 19:16
 * @Version 1.0
 */
public interface UserService {

    User queryByUserName(String userName);
}

  • 新建service层接口实现类
package com.shiro.test.shiro.service.impl;

import com.shiro.test.shiro.entity.User;
import com.shiro.test.shiro.mapper.UserMapper;
import com.shiro.test.shiro.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @Description
 * @ClassName UserServiceImpl
 * @Author yuhuofei
 * @Date 2021/11/21 19:17
 * @Version 1.0
 */
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Override
    public User queryByUserName(String userName) {
      User user = userMapper.queryByUserName(userName);
      return user;
    }
}

  • 新建controller类,对外暴露接口
package com.shiro.test.shiro.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.ResponseBody;

/**
 * @Description
 * @ClassName UserController
 * @Author yuhuofei
 * @Date 2021/11/21 12:02
 * @Version 1.0
 */
@Controller
public class UserController {

    @RequestMapping("/index")
    public String toIndex(Model model) {
        model.addAttribute("msg", "hello,Shiro");
        return "index";
    }

    @RequestMapping("/user/add")
    public String add() {
        return "/user/add";
    }

    @RequestMapping("/user/update")
    public String update() {
        return "/user/update";
    }


    @RequestMapping("/toLogin")
    public String toLogin() {
        return "login";
    }

    @RequestMapping({"/","/login"})
    public String login(String userName, String passWord, Model model) {
        model.addAttribute("msg", "hello,Shiro");
        //获取当前登录用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(userName, passWord);
        //执行登录
        if (userName != null) {
            try {
                subject.login(token);
                return "index";
            } catch (UnknownAccountException e) {//用户名不存在
                model.addAttribute("msg", "用户名错误");
                return "login";
            } catch (IncorrectCredentialsException e) {//密码错误
                model.addAttribute("msg", "密码错误");
                return "login";
            }
        }
        return "login";
    }

    @RequestMapping("/unAuth")
    @ResponseBody
    public String unAuth() {

        return "未经授权,无法访问!";
    }

    @RequestMapping("/logout")
    public String logout() {
        //获取当前登录用户
        Subject subject = SecurityUtils.getSubject();
        //退出登录
        subject.logout();
        return "/login";
    }
}

5、测试

在数据库的user表中,新增两个用户root、jack,分别赋予root用户新增的权限,jack修改的权限。

5.1 启动项目

在这里插入图片描述

5.2 使用root用户登录

在这里插入图片描述
登录后,进到首页,由于root用户只有新增的权限,没有修改的权限,所以不能看到修改的菜单

在这里插入图片描述
点击新增,进到新增页面

在这里插入图片描述
点击首页的退出,回到登录页面

在这里插入图片描述

5.3 使用jack用户登录

在这里插入图片描述
成功登录到首页,jack用户只有修改权限,所以看不到新增的菜单
在这里插入图片描述
点击修改,进到update页面
在这里插入图片描述
点击首页的退出,回到登录页面
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值