springboot整合shiro做权限

springboot集成Shiro

说明

1, 什么是shiro
Apache Shiro 是Java 的一个安全框架。Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE 环境,也可以用在JavaEE 环境。Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与Web 集成、缓存等。

2,为什么要学shiro
1,既然shiro将安全认证相关的功能抽取出来组成一个框架,使用shiro就可以非常快速的完成认证、授权等功能的开发,降低系统成本。

2,shiro使用广泛,shiro可以运行在web应用,非web应用,集群分布式应用中越来越多的用户开始使用shiro。
java领域中spring security(原名Acegi)也是一个开源的权限管理框架,但是spring security依赖spring运行,而shiro就相对独立,最主要是因为shiro使用简单、灵活,所以现在越来越多的用户选择shiro。

3,基本功能

在这里插入图片描述

1,Authentication
身份认证/登录,验证用户是不是拥有相应的身份;

2, Authorization
授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用
户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用
户对某个资源是否具有某个权限;

3, Session Manager
会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信
息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

4,Cryptography
加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

5,Web Support
Web 支持,可以非常容易的集成到Web 环境;

6,Caching
缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

7,Concurrency
shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能 把权限自动传播过去;

8,Testing
提供测试支持;

9,Run As
允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

10,Remember Me
记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

注意:Shiro 不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过 相应的接口注入给Shiro即可。关于设计,后面的ssm集成shiro里面去说哦

4,架构说明
1,Subject
Subject即主体,外部应用与subject进行交互,subject记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。 Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权

2,SecurityManager
SecurityManager即安全管理器,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。
SecurityManager是一个接口,继承了Authenticator, Authorizer, SessionManager这三个接口。

3,Authenticator
Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。

4,Authorizer
Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。

5,realm
Realm即领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。
注意:不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码。

6,sessionManager
sessionManager即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。

7,SessionDAO
SessionDAO即会话dao,是对session会话操作的一套接口,比如要将session存储到数据库,可以通过jdbc将会话存储到数据库。

8,CacheManager
CacheManager即缓存管理,将用户权限数据存储在缓存,这样可以提高性能。

9,Cryptography
Cryptography即密码管理,shiro提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。

实战

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.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.shen</groupId>
    <artifactId>shiro-springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shiro-springboot</name>
    <description>shiro-springboot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--subject:用户
           SecurityManager 管理所有用户
           Realm 连接数据
          -->
        <!-- 导入shiro整合包-->
        <!--shiro-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>
        <!--整合 shiro-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.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-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--thymeleaf模板 -->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-java8time</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </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>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>

    </dependencies>

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

</project>

首先建一个config

ShiroConfig

package com.shen.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;

/**
 * @program: springBoot-shiro
 * @description: Shiro配置类
 * @author: Mr.shen
 * @create: 2022-07-18 15:40
 **/
@Configuration
public class ShiroConfig {


    //ShiroFilterFactoryBean:3
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        //添加shiro的内置过滤器
        /***
         *  anon:无需认证就可以访问
         *  authc:必须认证了才能访问
         *  user:必须拥有记住我功能才能用
         *  perms:拥有对某个资源的权限才能访问
         *  role:拥有某个角色权限才能访问
         *  支持通配符
         */
        Map<String, String> filterMap = new LinkedHashMap<>();
//        filterMap.put("/user/add", "authc");
//        filterMap.put("/user/update", "authc");
//        filterMap.put("/user/*", "authc");
        //授权
        filterMap.put("/user/add", "perms[user:add]");
        filterMap.put("/user/update", "perms[user:update]");
        bean.setFilterChainDefinitionMap(filterMap);
        //如果没有权限设置跳转到toLogin (设置登录的请求)
        bean.setLoginUrl("/toLogin");
        //未授权页面
        bean.setUnauthorizedUrl("/noauth");
        return bean;

    }

    //DafaullWebSecurityManager:2

    /***
     * @Autowired默认是根据类型进行注入的,因此如果有多个类型一样的Bean候选者,则需要限定其中一个候选者,否则将抛出异常
     * @Qualifier限定描述符除了能根据名字进行注入,更能进行更细粒度的控制如何选择候选者
     * @param userRealm
     * @return
     */
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联UserRealm
        securityManager.setRealm(userRealm);

        return securityManager;
    }

    //创建reaml对象 ,需要自定义对象:1
    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }

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

}

UserRealm(授权和认证)

package com.shen.config;

import com.shen.pojo.User;
import com.shen.service.UserService;
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;
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;

/**
 * @program: springBoot-shiro
 * @description: 授权和验证
 * @author: Mr.shen
 * @create: 2022-07-18 15:50
 **/
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService service;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行=>>授权doGetAuthorizationInfo");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //拿到当前登录得这个对象
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        //设置当前用户得权限    @user.getPerms():数据库赋予了什么权限
        info.addStringPermission(user.getPerms());
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("执行=>>doGetAuthenticationInfo");
        //连接数据库
        UsernamePasswordToken userToken = (UsernamePasswordToken) token;
        User user = service.queryUserByName(userToken.getUsername());
        if (user == null) {
            return null;
        } else {

        }
        //密码可以加密正常是md5 md5盐值加密
        //密码认证shiro自己帮我们做
        //第一个参数是传递得资源也就是对象 第二个是验证密码
        return new SimpleAuthenticationInfo(user, user.getPwd(), "");
    }
}

Mycontroller

package com.shen.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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @program: springBoot-shiro
 * @description:
 * @author: Mr.shen
 * @create: 2022-07-18 15:31
 **/
@Controller
public class Mycontroller {
    @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 m) {
        //获取当前的用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        /***
         * @UnknownAccountException:用户名不存在
         * @IncorrectCredentialsException:密码不存在
         */
        try {
            subject.login(token); //执行登录方法,如果没有异常就说明OK了
            return "index";

        } catch (UnknownAccountException E) {

            m.addAttribute("msg", "用户名错误");
            return "login";
        } catch (IncorrectCredentialsException e) {
            m.addAttribute("msg", "密码错误");
            return "login";
        }
    }

    @RequestMapping("/noauth")
    @ResponseBody
    public String noauth() {
        return "未经授权无法访问此页面";
    }
}

项目结构

dex";

    } catch (UnknownAccountException E) {

        m.addAttribute("msg", "用户名错误");
        return "login";
    } catch (IncorrectCredentialsException e) {
        m.addAttribute("msg", "密码错误");
        return "login";
    }
}

@RequestMapping("/noauth")
@ResponseBody
public String noauth() {
    return "未经授权无法访问此页面";
}

}


**项目结构**

![在这里插入图片描述](https://img-blog.csdnimg.cn/68e723f1d0cd42c6928ce953529f495e.png#pic_center)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值