SpringBoot-Shiro

shiro

shiro核心API

subject:用户主题

SecurityManager: 安全管理器 管理对象 封装shiro功能

Realm:shiro连接数据库的桥梁,数据的提供者

目录结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C9rX4vr7-1629448963989)(shiro.assets/image-20210820110830949.png)]

SpringBootApplication.java

@SpringBootApplication
@MapperScan(value = {"com.gxh.modules.**.mapper*"})
public class ShiroApplication {

    public static void main(String[] args) throws Exception{
        Long s1 = System.currentTimeMillis();
        ConfigurableApplicationContext application = SpringApplication.run(ShiroApplication.class, args);
        Long s2 = System.currentTimeMillis();

        Environment env = application.getEnvironment();
        String ip = InetAddress.getLocalHost().getHostAddress();
        String port = env.getProperty("server.port");
        String path = env.getProperty("server.servlet.context-path");

        System.out.println("=======================================>");
        System.out.println("启动耗时=======>"+(s2-s1));
        System.out.println("ip:http://localhost:" + port + path);
        System.out.println("serve start-up success");
        System.out.println("=======================================>");
    }
}

application.yml

server:
  port: 8089
  servlet:
    context-path: /

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/#{你的数据库}?useSSL=true&useUnicode=true&characterEncoding=UTF-8
    username: #{你的账号}
    password: #{你的密码}
  resources:
    static-locations: classpath:/static/,classpath:/templates/
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8



mybatis-plus:
  mapper-locations: classpath*:com/gxh/modules/**/xml/*Mapper.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  #  关闭mybatis-plus启动banner
  global-config:
    banner: false
#logging:
#  level:
#    com.lxito.mapper: debug

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.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.14</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.22</version>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.10</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.68</version>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.10</version>
        </dependency>


        <!-- mybatis-plus相关依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </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>

        <!--加入验证码随机数-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.10</version>
        </dependency>

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

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

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

        </plugins>
        <!--生产xml-->
        <!-- 如果不添加此节点mybatis的mapper.xml文件都会被漏掉。 -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.yml</include>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.yml</include>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                    <include>**/*.html</include>
                    <include>**/*.css</include>
                    <include>**/*.js</include>
                    <include>**/*.*</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>
<!--次pom为项目所需要用到的依赖以及 buil-->

整合shiro

 /***
     * 创建一个过滤器工厂
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean filterFactory= new ShiroFilterFactoryBean();
        //安全管理器
        filterFactory.setSecurityManager(securityManager);
        return filterFactory;
    }

    /***
     * 创建安全管理器
     */
    @Bean
    public DefaultWebSecurityManager securityManager(ShiroRealm realm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //给管理器赋值realm
        securityManager.setRealm(realm);
        return securityManager;
    }

    /**
     * 配置自定义realm
     */
    @Bean
    public ShiroRealm userRealm(){
        ShiroRealm realm = new ShiroRealm();
        return realm;
    }

3.1 编写shiro相关配置类

package com.gxh.modules.config;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/***
 * shiro 配置类
 */
@Configuration
public class ShiroConfig {

    /***
     * 创建一个过滤器工厂
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean filterFactory= new ShiroFilterFactoryBean();
        //安全管理器
        filterFactory.setSecurityManager(securityManager);
        return filterFactory;
    }

    /***
     * 创建安全管理器
     */
    @Bean
    public DefaultWebSecurityManager securityManager(ShiroRealm realm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //给管理器赋值realm
        securityManager.setRealm(realm);
        return securityManager;
    }

    /**
     * 配置自定义realm
     */
    @Bean
    public ShiroRealm userRealm(){
        ShiroRealm realm = new ShiroRealm();
        return realm;
    }
}

3.2使用shiro内置拦截器实现页面拦截

LinkedHashMap<String,String> map = new LinkedHashMap<String, String>();
        /**
         * shiro内置过滤器
         *  常用过滤器
         *  anon:不需要认证就可以直接访问
         *  authc: 必须需要认证才可以访问的页面
         *  user: 如果使用了记住我的功能可以直接访问页面
         *  perms: 必须得到资源权限才可以访问
         *  role: 必须得到角色权限才可以访问
         */
        //假设用户主页都可以访问,增删该必须认证后才可以访问
        map.put("/user","anon");  //不需要认证
        map.put("/add","authc");  //需要认证
        map.put("/update","authc");  //需要认证
        map.put("/delete","authc");  //需要认证
        filterFactory.setFilterChainDefinitionMap(map);
        //设置登录页
        filterFactory.setLoginUrl("/login");

认证获取数据库中的数据进行比对

/**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("认证");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        User user = userService.findAllByName(token.getUsername());
        //判断
        if (ObjectUtils.isEmpty(user)){
            return null;
        }
        return new SimpleAuthenticationInfo("",user.getPassword(),"");
    }

授权

 //只有达到权限后才可以执行
        map.put("/add","perms[user:insert]");
        map.put("/update","perms[user:update]");
//在shiroconfig中将insert和update设置为 "必须得到资源权限才可以访问"
/**     * 授权     * @param principalCollection     * @return     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {        System.out.println("授权");        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        //添加资源授权的字符串 保证配置一样        info.addStringPermission("user:insert");//        info.addStringPermission("user:update");        return info;    }

controller层

@RequestMapping("/login")public String index(){    return "pages/login";}@RequestMapping("/add")public String addUser(){    return "pages/add";}@RequestMapping("/update")public String updateUser(){    return "pages/update";}@RequestMapping("/delete")public String deleteUser(){    return "pages/delete";}@RequestMapping("/user")public String userIndex(){    return "pages/user";}/** * 登录 */@RequestMapping("/loginIn")public String loginIn(String username, String password, Model model){    //shiro编写认证操作    //1 获取subject    Subject subject = SecurityUtils.getSubject();    //2 封装用户数据    UsernamePasswordToken token = new UsernamePasswordToken(username,password);    //3 执行登录方法    try {        subject.login(token);        //跳转到成功页面        return "pages/user";    }catch (UnknownAccountException e){        model.addAttribute("msg","用户名不存在");        return "pages/login";    }catch (IncorrectCredentialsException e){        model.addAttribute("msg","密码不正确");        return "pages/login";    }}/*** * 设置未授权页面 */@RequestMapping("/noPermission")public String noPermission(){    return "pages/noPermission";}

mapper层

package com.gxh.modules.mapper;import com.gxh.modules.po.User;import org.apache.ibatis.annotations.Param;import org.springframework.stereotype.Repository;@Repositorypublic interface SysUserMapper {    /***     * 根据用户名查询信息     */    public User findAllByName(@Param("username") String username);}

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.gxh.modules.mapper.SysUserMapper">    <select id="findAllByName" parameterType="java.lang.String" resultType="com.gxh.modules.po.User">        select * from `sys_user` where username = #{username}    </select></mapper>

页面展示层

login.html
<!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head>    <meta charset="UTF-8">    <title>登录</title></head><body><h2 th:text="${msg}"></h2><h1>登录功能</h1><form method="post" action="loginIn">    用户名:<input type="text" name="username"><br/>    密 码: <input type="password" name="password"><br/>    <input type="submit" value="登录"></form></body></html>
user.html
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    用户管理页面    <a href="add">用户添加</a>    <a href="update">用户修改</a>    <a href="delete">用户删除</a></body></html>
add.html
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>用户添加</body></html>
update.html
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>用户修改</body></html>
delete.html
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>用户删除</body></html>
nopermission.html
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>permission</title></head><body>    未授权;若想拥有此权限,请联系管理员配置权限!</body></html>

动态获取权限

修改数据库表结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VW6JgH9g-1629448963991)(shiro.assets/image-20210820100852422.png)]

执行授权位置修改动态权限菜单

 /**     * 授权     * @param principalCollection     * @return     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {        System.out.println("授权");        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        //添加资源授权的字符串 保证配置一样        //info.addStringPermission("user:insert");        //info.addStringPermission("user:update");        //动态查询数据库权限        Subject subject = SecurityUtils.getSubject();        //获取对象        User user = (User) subject.getPrincipal();        //获取用户对象的权限        info.addStringPermission(user.getPermission());        return info;    }
/**     * 认证     * @param authenticationToken     * @return     * @throws AuthenticationException     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {        System.out.println("认证");        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;        User user = userService.findAllByName(token.getUsername());        //判断        if (ObjectUtils.isEmpty(user)){            return null;        }        return new SimpleAuthenticationInfo(user,user.getPassword(),"");    }

1.创建表结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q4pKoG67-1629448963992)(shiro.assets/image-20210820104552401.png)]

2.功能模拟

账号密码备注
admin123456所有权限
gxh123456具有用户管理权限
other123456具备添加,修改权限

3.创建想关的实体类对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xkG4SVHf-1629448963993)(shiro.assets/image-20210820111845271.png)]

4.导入数据库五张表以及数据信息

注:源码放在最后,请根据目录结构自行创建,所需要的资源请继续往下看!

5.Mapper层接口

    /***     * 根据用户名查询信息     */    public User findAllByName(@Param("username") String username);    /**     * 根据用户id查询信息     * @param id     */    User queryUserById(@Param("id")Integer id);    /***     * 根据id查询权限 和 url标识     * @param id     */    List<User> findUrlAndPermByUserId(@Param("id") Integer id);    /***     * 查询按钮级别的权限     * @param id     */    List<Menu> queryMenuUrlAndPermUserId(@Param("id") Integer id);

mapper实现层

 <select id="findAllByName" parameterType="java.lang.String" resultType="com.gxh.modules.po.User">        select * from `user` where username = #{username}    </select>    <!--根据用户id查询信息-->    <select id="queryUserById" parameterType="java.lang.Integer" resultType="com.gxh.modules.po.User">        select * from `user` where id = #{id}    </select>    <!--根据id查询权限 和 url标识-->    <select id="findUrlAndPermByUserId" parameterType="java.lang.Integer" resultType="com.gxh.modules.po.User">        SELECT	    DISTINCT url,	        permission        FROM        	`user` u        LEFT JOIN user_role ur ON ur.user_id = u.id        LEFT JOIN role r ON r.id = ur.role_id        LEFT JOIN role_menu rm ON rm.role_id = r.id        LEFT JOIN menu m ON m.id = rm.menu_id        WHERE m.type in (1,0)        <if test="id != null and id != ''">            and u.id = #{id}        </if>    </select>    <!--查询按钮级别的权限-->    <select id="queryMenuUrlAndPermUserId" parameterType="java.lang.Integer"            resultType="com.gxh.modules.po.Menu">        SELECT        DISTINCT url,        permission        FROM        `menu` m        LEFT JOIN role_menu rm ON rm.menu_id = m.id        LEFT JOIN `role` r ON rm.id = r.id        LEFT JOIN user_role ur ON ur.role_id = r.id        LEFT JOIN `user` u ON  u.id = ur.user_id        WHERE m.type = '2'        <if test="id != null and id != ''">            and u.id = #{id}        </if>    </select>

service层

    /***     * 根据用户名查询信息     */    public User findAllByName(String username);    /**     * 根据用户id查询信息     * @param id     */    User queryUserById(Integer id);    /***     * 根据id查询权限 和 url标识     * @param id     */    List<User> findUrlAndPermByUserId(Integer id);    /***     * 查询按钮级别的权限     * @param id     */    List<Menu> queryMenuUrlAndPermUserId(Integer id);

ServiceImpl

@Service@RequiredArgsConstructor(onConstructor = @__(@Autowired))public class SysUserServiceImpl implements SysUserService {    private final SysUserMapper userMapper;    @Override    public User findAllByName(String username) {        return userMapper.findAllByName(username);    }    @Override    public User queryUserById(Integer id) {        return userMapper.queryUserById(id);    }    @Override    public List<User> findUrlAndPermByUserId(Integer id) {        return userMapper.findUrlAndPermByUserId(id);    }    @Override    public List<Menu> queryMenuUrlAndPermUserId(Integer id) {        return userMapper.queryMenuUrlAndPermUserId(id);    }}

编写全向控制想关工具类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qnbOdM2V-1629448963994)(shiro.assets/image-20210820151859242.png)]

注: 此类若想在其他类中注入一定要在类上加@Component(“shiroUtils”) 注解

@Component("shiroUtils")
public class ShiroUtils {

    @Autowired
    private SysUserService userService;


    /***
     * 获取过滤配置
     */
    public Map<String,String> perms(){
        LinkedHashMap<String,String> map = new LinkedHashMap<String,String>();
        /**
         * shiro内置过滤器
         *  常用过滤器
         *  anon:不需要认证就可以直接访问
         *  authc: 必须需要认证才可以访问的页面
         *  user: 如果使用了记住我的功能可以直接访问页面
         *  perms: 必须得到资源权限才可以访问
         *  role: 必须得到角色权限才可以访问
         */
        //假设用户主页都可以访问,增删该必须认证后才可以访问
        map.put("login","anon");
        map.put("/loginIn","anon");  //不需要认证
        //只有达到权限后才可以执行
        map.put("/**","authc");  //需要认证
        return map;
    }


    /**
     * 获取权限列表
     */
    public List<Menu> queryPerm(Integer userId){
        List<Menu> menuList = userService.queryMenuUrlAndPermUserId(userId);
        return menuList;
    }

然后再ShiroConfig和ShiroRealm中可以这样写

ShiroConfig

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s5KJhTyD-1629448963994)(shiro.assets/image-20210820152207871.png)]

注入ShiroUtils

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-93tQm90R-1629448963995)(shiro.assets/image-20210820152235705.png)]加入ShiroDialect

    /**
     * 配置shiro和thymeleaf标签
     */
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }

ShiroRealm

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kpl6o7SL-1629448963995)(shiro.assets/image-20210820152251615.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9wXMv5FK-1629448963996)(shiro.assets/image-20210820152309867.png)]

Springboot启动类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mdFbF2Cp-1629448963997)(shiro.assets/image-20210820154216322.png)]

页面菜单权限的控制

创建对应的功能页面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dxRGgAzZ-1629448963997)(shiro.assets/image-20210820162004105.png)]

Contoller层

@Controller
public class BaseController {

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

    @RequestMapping("/addUser")
    public String addUser(){
        return "pages/page/addUser";
    }

    @RequestMapping("/updateUser")
    public String updateUser(){
        return "pages/page/updateUser";
    }

    @RequestMapping("/deleteUser")
    public String deleteUser(){
        return "pages/page/deleteUser";
    }

    @RequestMapping("/user")
    public String userIndex(){
        return "pages/page/user";
    }


    @RequestMapping("/addDept")
    public String addDept(){
        return "pages/page/addDept";
    }

    @RequestMapping("/updateDept")
    public String updateDept(){
        return "pages/page/updateDept";
    }

    @RequestMapping("/deleteDept")
    public String deleteDept(){
        return "pages/page/deleteDept";
    }

    @RequestMapping("/dept")
    public String dept(){
        return "pages/page/dept";
    }
}

前台页面处理

加入相关约束
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.w3.org/1999/xhtml">
权限标签
<a href="addDept" shiro:hasPermossion="dept:insert">添加</a>
<a href="updateDept" shiro:hasPermossion="dept:update">修改</a>
<a href="deleteDept" shiro:hasPermossion="dept:delete">删除</a>

注意点:

dept:insert dept:update dept:delete

和数据库表菜单信息表中的权限标识符保持一直即可

以上只是简单的权限控制,并没有才用到密码的散列加密等,如果想学可以看这个连接
一片非常适合小白的shiro教程

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白的小,小白的白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值