SpringBoot&Shiro入门笔记

第一章 Shiro简介

1.1 什么是Shiro?

Apache Shiro 是一个强大易用的 Java 安全框架,提供了认证、授权、加密和会话管理等功能,对于任何一个应用程序,Shiro 都可以提供全面的安全管理服务。并且相对于其他安全框架,Shiro 要简单的多。

1.2 Shiro框架结构

shiro是一个独立的安全框架,不跟任何的框架或者容器捆绑,可以独立运行,完整的框架结构如下
在这里插入图片描述

1.2.1 Shiro主要三大核心注件

三个核心组件:Subject, SecurityManagerRealms
Subject:即“当前操作用户”。不仅仅是指人,可以是第三方的应用交互,比如,后台进程自己访问应用。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。

1.2.2 主要功能

Authentication:身份认证 / 登录,验证用户是不是拥有相应的身份;
Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
Session Management:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通 JavaSE 环境的,也可以是如 Web 环境的;
Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
Web Support:Web 支持,可以非常容易的集成到 Web 环境;
Caching:缓存,比如用户登录后,其用户信息、拥有的角色 / 权限不必每次去查,这样可以提高效率;
Concurrency:shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
Testing:提供测试支持;
Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
Remember Me:记住我功能,开启默认下次不用登录。
在这里插入图片描述

第二章 认证

2.1 新建一个springboot项目

  1. 完整的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>
    <groupId>com.lyf.shiro</groupId>
    <artifactId>shiro</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shiro</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
        <shiro.version>1.5.1</shiro.version>
        <thymeleaf.extras.shiro.version>2.1.0</thymeleaf.extras.shiro.version>

    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.4</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>${thymeleaf.extras.shiro.version}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <!-- Shiro+JWT start -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <!-- Shiro end -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</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.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.lyf.shiro.ShiroApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>


  1. 创建ShiroConfig.java
package com.lyf.shiro.config;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
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;

import java.util.LinkedHashMap;
import java.util.Map;


/**
 * @Author: lyf
 * @CreateTime: 2022-11-17
 * @description: Shiro配置
 */

@Configuration
public class ShiroConfig {
    /**
     * 定义一个默认的安全管理器,这个管理器将管理所有的Shiro组件实例,
     * @param realm 用于访问数据源的域
     * @return
     */
    @Bean
    public SecurityManager securityManager(Realm realm){
        //创建一个默认的实例放入到ioc容器当中
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(realm);
        return  defaultWebSecurityManager;
    }

    /**
     * 定义一个数据源域,这个域Realm需要自己去实现
     * @return
     */
    @Bean
    public MyRealm realm(){
        MyRealm myRealm = new MyRealm();
        return myRealm;
    }

    /**
     * 定义一个过滤器,过滤所有的请求
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        shiroFilter.setLoginUrl("/");
        shiroFilter.setSuccessUrl("/success");
        shiroFilter.setUnauthorizedUrl("/noPermission");

        Map<String,String> filterMap = new LinkedHashMap<>();
        /**
         /admin/**  表示一个请求名字的通配, 以admin开头的任意子路径下的所有请求
         * anon: 表示该路径不需要进行认证,已访客身份访问
         authc 表示该路径需要进行认证(登录),只有认证(登录)通过才能访问
         ** 表示任意子路径
         *  表示任意的一个路径
         ? 表示 任意的一个字符
         */
        filterMap.put("/login","anon");
        filterMap.put("admin/**","authc");
        filterMap.put("user/**","authc");
        //注释表示拦截所有路径的请求,如果换成anon,则放行所有的请求路径
        filterMap.put("/**","authc");
        shiroFilter.setFilterChainDefinitionMap(filterMap);
        return shiroFilter;
    }
}

  1. 创建MyRealm.java
package com.lyf.shiro.config;

import org.apache.shiro.authc.*;
import org.apache.shiro.realm.Realm;

/**
 * @Author: lyf
 * @CreateTime: 2022-11-17
 * @description:
 */
public class MyRealm implements Realm {

    /**
     * 返回这个域的名称
     * @return
     */
    @Override
    public String getName() {
        return "MyRealm";
    }

    /**
     * 表示是否开启这个域的验证,为true表示开启,为false表示不开启这个域的验证
     * @param token
     * @return
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return true;
    }


    /**
     * 登录验证需要执行的方法,在主题调用subject.login(token),具体的验证就会有SecurityManager调用到这个方法进行验证;
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        UsernamePasswordToken  usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        char[] password = usernamePasswordToken.getPassword();

        if ("admin".equals(username)&&"123".equals(password)){
            //返回验证通过的信息到授权的处理器,授权处理器根据传人的参数设置角色与权限
            return new SimpleAuthenticationInfo(username,password,getName());
        }else {
		throw  new AuthenticationException("登录失败");
        }
    }

}

  1. 定义 login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="login" method="post">
    username:<input name="username" type="text"><br>
    password:<input type="password" name="password"><br>
    <input type="submit" value="submit">
</form>
</body>
</html>
  1. 定义 success.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>


<h1>登录成功</h1>
</body>

</html>
  1. 定义 noPermission.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>

<h1>对不起!您没有权限操作!</h1>
</body>

</html>
  1. 定义 loginController.java
@Controller
public class loginController {


    /**
     * 跳转到登录页面
     * @return
     */
    @RequestMapping("/")
    public String toLogin(){
        return "login";
    }
    /**
     * 登录控制器
     * @param username 用户名
     * @param password 密码
     * @param response 客户端响应,输入错误信息
     * @return
     * @throws IOException
     */
    @PostMapping("/login")
    public String login(String username, String password, HttpServletResponse response) throws IOException {

        PrintWriter writer = response.getWriter();
       // response.setCharacterEncoding("UTF-8");
        //shiro 提供的一个用户与密码的实现类,可以把用户提供的凭证信息封装成token
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password);
        //获取当前的主体(当前登录的对象)
        Subject subject = SecurityUtils.getSubject();
        //判断当前对象是否登录
        if (!subject.isAuthenticated()) {
            try {
                //每次登录前,执行登出操作,清空缓存
                subject.logout();
                //主体调用这个登录方法会跳转到realm中去执行验证
                subject.login(usernamePasswordToken);
            } catch (UnknownAccountException e) {
                writer.write("账号不存在!");
                writer.close();
                return "login";
            } catch (LockedAccountException e) {
                writer.write("账号被锁定");
                writer.close();
                return "login";
            }
        }
        return "redirect:success";
    }


    /**
     * 登录成功跳转页面
     * @return
     */
    @RequestMapping("/success")
    public String success(){
        return "success";
    }
    /**
     *无权限页面
     * @return
     */
    @RequestMapping("/noPermission")
    public String noPermiss(){
        return "noPermission";
    }
    /**
     * user/** 下的所有路径
     * @return
     */
    @RequestMapping("/user/add")
    public String user(){
        return "";
    }

    /**
     * 访问admin/** 下所有路径
     * @return
     */
    @RequestMapping("/admin/add")
    public String admin(){
        return "";
    }
}

2.2 测试接口

访问login
在这里插入图片描述
登录成功

在这里插入图片描述
访问user/add 或者admin/add 会跳转到登录页面。
**总结:**到这里,shiro的简单认证就完成了

2.3 登录流程总结

principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个 principals,但只有一个 Primary principals,一般是用户名 / 密码 / 手机号。
credentials:证明 / 凭证,即只有主体知道的安全值,如密码 / 数字证书等。
最常见的 principals 和 credentials 组合就是用户名 / 密码了。
另外两个相关的概念是之前提到的 Subject 及 Realm,分别是主体及验证主体的数据源。
登录流程:
1.首先调用 Subject.login(token) 进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils.setSecurityManager() 设置;
2.SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;
3.Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;
4.Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;
5.Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证成功了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访。

2.3.1 登录认证策略

FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第一个 Realm 身份验证成功的认证信息,其他的忽略;

AtLeastOneSuccessfulStrategy:只要有一个 Realm 验证成功即可,和 FirstSuccessfulStrategy 不同,返回所有 Realm 身份验证成功的认证信息;

AllSuccessfulStrategy:所有 Realm 验证成功才算成功,且返回所有 Realm 身份验证成功的认证信息,如果有一个失败就失败了。ModularRealmAuthenticator 默认使用 AtLeastOneSuccessfulStrategy 策略。
Shiro支持的各种数据域结构图:
在这里插入图片描述
AuthorizingRealm授权域继承了AuthenticatingRealm认证域的类,所以我们只需要继承AuthorizingRealm域就可以实现自己的认证与授权操作。

package com.lyf.shiro.config;

import com.lyf.shiro.jwt.JwtToken;
import com.lyf.shiro.user.domain.Role;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * @Author: lyf
 * @CreateTime: 2022-11-17
 * @description:
 */
public class MyAuthenticatingRealm extends AuthorizingRealm {


    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return super.supports(token);
    }

/**
     * 登录认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

    }
/**
     * 授权,设置对应主体的角色与权限信息
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }
}

第三章 授权

3.1授权方式

1.通过代码授权,使用subject主体实例去实现

2.通过注解的方式
@RequiresAuthentication:使用该注解标注的类,实例,方法在访问或调用时,当前Subject必须在已经过认证。
@RequiresGuest:使用该注解标注的类,实例,方法在访问或调用时,当前Subject可以是gust身份,不需要经过认证或者在原先的session中存在记录。
@RequiresPermissions:当前Subject需要拥有某些特定的权限时,才能执行被该注解标注的方法。如果当前Subject不具有这样的权限,则方法不会被执行。
@RequiresRoles:当前Subject必须拥有所有指定的角色时,才能访问被该注解标注的方法。如果当天Subject不同时拥有所有指定角色,则方法不会执行还会抛出AuthorizationException异常。
@RequiresUser:当前Subject必须是应用的用户,才能访问或调用被该注解标注的类,实例,方法。

    @RequiresGuest
    @RequiresUser
    @RequiresAuthentication
    @RequiresRoles("admin")
    @RequiresPermissions("sys:user:view")
    public String test(){
        return "null";
    }
  1. 通过页面方式
    在这里插入图片描述

3.2 权限通配符

规则:“资源标识符:操作:对象实例 ID” 即对哪个资源的哪个实例可以进行什么操作。其默认支持通配符权限字符串,“:”表示资源/操作/实例的分割;“,”表示操作的分割;“*”表示任意资源/操作/实例
1.操作单个权限 @RequiresPermissions(“system:user:update”)

2.操作多个权限 @RequiresPermissions({“system:user:update,system:user:delete”})如果拥有两个权限可以简写@RequiresPermissions({“system:user:update,delete”})

3.拥有全部权限 @RequiresPermissions(“system:user:")或者@RequiresPermissions(“system:user”)
4.单个权限 @RequiresPermissions(
:view*”)

5.单个实例的单个权限 @RequiresPermission(“user:view:1”) 表示实例1对当前资源有访问权限。
6.Shiro 对权限字符串缺失部分的处理。
前缀匹配原则:如(“system:delete:”)等价于(“system:delete:*”),而(“system”)等价于(“system: * ”)与(“system: * : *”);这样就完成了前缀匹配。
后缀匹配原则:如(“ :update”)不能匹配(“system:user:update”)需要知道全部匹配规则,如(“ * : :update”)才能匹配到相应的资源。

3.3 代码授权演示

这个继承了AuthorizingRealm 类,而该类又继承了认证类AuthenticatingRealm,所以我们在一个realm中实现自己的认证与授权方法。

package com.lyf.shiro.config;

import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;

import java.util.HashSet;
import java.util.Set;

/**
 * @Author: lyf
 * @CreateTime: 2022-11-17
 * @description:
 */
public class MyRealm extends AuthorizingRealm {
    /**
     * 返回这个域的名称
     * @return
     */

    @Override
    public String getName() {
        return super.getName();
    }

    /**
     * 表示是否开启这个域的验证,为true表示开启,为false表示不开启这个域的验证
     * @param token
     * @return
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return super.supports(token);
    }


    /**
     * 授权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        //获取主要的身份信息这里获取到的是认证SimpleAuthenticationInfo(username,password,getName());传过来的用户名
        //通过用户名去数据库查询角色权限信息,这个做一个简单的角色权限封装
        String primaryPrincipal = (String) principals.getPrimaryPrincipal();
        //角色集合
        Set<String> role = new HashSet<>();
        //permission集合
        Set<String> permission = new HashSet<>();

        if ("admin".equals(primaryPrincipal)){
            role.add("admin");
            role.add("user");
            permission.add("system:user:*");
            permission.add("system:admin:add");
        }else {
            role.add("user");
           permission.add("system:user:add");
       }
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(role);
        simpleAuthorizationInfo.setStringPermissions(permission);
        return  simpleAuthorizationInfo;
    }
    /**
     * 登录验证需要执行的方法,在主题调用subject.login(token),
     * 具体的验证就会有SecurityManager调用到这个方法进行验证;
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        UsernamePasswordToken  usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        String password = usernamePasswordToken.getPassword().toString();

        /**
         * 这个的用户名与密码应该从数据库拿到然后做对比的,我这里做了简单地点封装
         */
        if ("admin".equals(username)||"user".equals(username)){
            //返回验证通过的信息到授权的处理器,授权处理器根据传人的参数设置角色与权限
            return new SimpleAuthenticationInfo(username,password,getName());
        }else {
            throw  new AuthenticationException("登录失败");
        }

    }
}


CredentialsMatcher类是拥有密码匹配认证,如果正确返回true;

public class MyCredentialsMatcher implements CredentialsMatcher {

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
       UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        System.out.println(usernamePasswordToken.getUsername());
        return true;
    }
}

修改ShiroConfig类的MyRealm类方法

 @Bean
    public MyCredentialsMatcher credentialsMatcher(){
        return  new MyCredentialsMatcher();
    }
 @Bean
    public MyRealm realm(){
        MyRealm myRealm = new MyRealm();
        myRealm.setCredentialsMatcher(credentialsMatcher());
        return myRealm;
    }

第四章 过滤器

4.1过滤器类关系

在这里插入图片描述
在这里插入图片描述
1、NameableFilter
NameableFilter 给 Filter 起个名字,如果没有设置默认就是 FilterName;还记得之前的如 authc 吗?当我们组装拦截器链时会根据这个名字找到相应的拦截器实例;

2、OncePerRequestFilter
OncePerRequestFilter 用于防止多次执行 Filter 的;也就是说一次请求只会走一次拦截器链;另外提供 enabled 属性,表示是否开启该拦截器实例,默认 enabled=true 表示开启,如果不想让某个拦截器工作,可以设置为 false 即可。

3、ShiroFilter
ShiroFilter 是整个 Shiro 的入口点,用于拦截需要安全控制的请求进行处理,这个之前已经用过了。

4、AdviceFilter
AdviceFilter 提供了 AOP 风格的支持,类似于 SpringMVC 中的 Interceptor
5、PathMatchingFilter
PathMatchingFilter 提供了基于 Ant 风格的请求路径匹配功能及拦截器参数解析的功能,如“roles[admin,user]”自动根据“,”分割解析到一个路径参数配置并绑定到相应的路径:
6、AccessControlFilter
AccessControlFilter 提供了访问控制的基础功能;比如是否允许访问/当访问拒绝时如何处理等

4.2 自定义过滤器

public class MyFilter extends AuthenticatingFilter {


    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        return false;
    }


    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
        return null;
    }

    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        return super.onLoginFailure(token, e, request, response);
    }
}

修改ShiroConfig类,设置过滤器

 @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        //自定义过滤器
        Map<String, Filter> myFilterMap = new HashMap<>();
        myFilterMap.put("FILTER",new MyFilter());
        shiroFilter.setFilters(myFilterMap);
		......

第五章 加密&解密

5.1 常用加密算法

Base64 加密&解密

/**
     * shiro提供的Base64编码与解码
     */
    @Test
    public void test(){
        String str = "hello world";
        String  encode = Base64.encodeToString(str.getBytes());
        System.out.println(encode);
        String decode = Base64.decodeToString(encode.getBytes());
        System.out.println(decode);

    }

MD5Hash加密

  @Test
    public void test1(){
        String source = "hello,world";
        String salt = "123";
     String password = new Md5Hash(source,salt).toString();
        System.out.println(password);
    }

Sha256Hash加密算法

		String source = "hello,world";
        String salt = "123";
String sha1 = new Sha256Hash(source , salt).toString();

SimpleHash加密算法

String str = "hello";
String salt = "123";
//内部使用MessageDigest
String simpleHash = new SimpleHash("SHA-1", str, salt).toString();  

AesCipherService加密&解密算法

 @Test
    public void test2(){
        AesCipherService aesCipherService = new AesCipherService();
        aesCipherService.setKeySize(128);//设置key的大小

        Key key = aesCipherService.generateNewKey();//生成一个key
        String password = "aesCipherService";//加密信息
        //加密
        String encryptPassword = aesCipherService.encrypt(password.getBytes(), key.getEncoded()).toHex();
        //解密
      String str=  new String(aesCipherService.decrypt(Hex.decode(encryptPassword),key.getEncoded()).getBytes());
      //输出原加密密文  
      System.out.println("str"+str);
    }

在这里插入图片描述

注入PasswordService服务类,即可调用加密算法

public interface PasswordService {
    //输入明文密码得到密文密码
    String encryptPassword(Object plaintextPassword) throws IllegalArgumentException;
}

第六章 会话管理

6.1shiro会话

shiro提供的会话不依赖任何底层容器,提供了会话管理、会话事件监听、会话存储 / 持久化、容器无关的集群、失效 / 过期支持、对 Web 的透明支持、SSO 单点登录的支持等特性。使用shiro的会话管理可以代替web的会话管理。

6.2会话获取

//获取当前的主体(当前登录的对象)
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();//通过主体获取当前会话
        session.setAttribute("name",subject.getPrincipal());//设置会话属性
        session.setTimeout(120L);//设置会话超时时间
        System.out.println("name:"+session.getAttribute("name"))//打印会话属性值

subject.getSession(true)如果为true,表示如果没有会话就创建一个会话,为false表示没有返回空。

 		//获取会话唯一id
        session.getId();
        //获取当前的主机
        session.getHost();
        //设置会话过期时间
        session.setTimeout(120L);
        //获取会话过期时间
        session.getTimeout();

获取会话的启动时间及最后访问时间;如果是 JavaSE 应用需要自己定期调用 session.touch() 去更新最后访问时间;如果是 Web 应用,每次进入 ShiroFilter 都会自动调用 session.touch() 来更新最后访问时间。当 Subject.logout() 时会自动调用 stop 方法来销毁会话。如果在 web 中,调用 javax.servlet.http.HttpSession. invalidate() 也会自动调用 Shiro Session.stop 方法进行销毁 Shiro 的会话

	 session.getLastAccessTime();
     session.getStartTimestamp();
     //更新会话最后访问的时间
        session.touch();
        //销毁会话
        session.stop();

6.3 会话管理

Session start(SessionContext context); //启动会话
Session getSession(SessionKey key) throws SessionException; //根据会话Key获取会话

在这里插入图片描述
Shiro 提供了三个默认实现:

DefaultSessionManager:DefaultSecurityManager 使用的默认实现,用于 JavaSE 环境;
ServletContainerSessionManager:DefaultWebSecurityManager 使用的默认实现,用于 Web 环境,其直接使用 Servlet 容器的会话;
DefaultWebSessionManager:用于 Web 环境的实现,可以替代 ServletContainerSessionManager,自己维护着会话,直接废弃了 Servlet 容器的会话管理。

第七章 RememberMe

7.1 开启记住我功能

UsernamePasswordToken实现了记住我功能,直接传人值即可

 UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password);
        usernamePasswordToken.setRememberMe(true);

第八章 缓存

8.1 开启缓存

开启shiro自带的缓存。
导入shiro缓存依赖

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.2.2</version>
        </dependency>

修改ShiroConfig配置类的Realm。添加缓存的实现,当缓存开启,第一次请求会去访问数据库的数据,后面的请求就不会去访问数据库,而是直接访问缓存当中的数据。

 //设置缓存管理器
        myRealm.setCacheManager(new EhCacheManager());
        //开启全局缓存
        myRealm.setCachingEnabled(true);
        //开启认证缓存
        myRealm.setAuthenticationCachingEnabled(true);
        //开启授权认证缓存
        myRealm.setAuthorizationCachingEnabled(true);
        return myRealm;

第八章 Shiro连接Mybatis

8.1 数据库脚本


/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50628
 Source Host           : localhost:3306
 Source Schema         : test

 Target Server Type    : MySQL
 Target Server Version : 50628
 File Encoding         : 65001

 Date: 22/11/2022 15:58:03
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;


-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission`  (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限名称',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES (1, 'system:user:update');
INSERT INTO `sys_permission` VALUES (2, 'system:user:insert');
INSERT INTO `sys_permission` VALUES (3, 'system:user:view');
INSERT INTO `sys_permission` VALUES (4, 'system:user:delete');
INSERT INTO `sys_permission` VALUES (5, 'system:admin:update');
INSERT INTO `sys_permission` VALUES (6, 'system:admin:insert');
INSERT INTO `sys_permission` VALUES (7, 'system:admin:view');
INSERT INTO `sys_permission` VALUES (8, 'system:*:*');

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色编号',
  `name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称',
  `desc` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色描述',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, 'admin', '用户权限');
INSERT INTO `sys_role` VALUES (2, 'guest', '管理权限');
INSERT INTO `sys_role` VALUES (3, 'user', '产品权限');
INSERT INTO `sys_role` VALUES (4, 'user1', '订单权限');

-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission`  (
  `id` bigint(20) NOT NULL COMMENT '主键',
  `role_id` bigint(16) NULL DEFAULT NULL COMMENT '角色id',
  `permission_id` bigint(20) NULL DEFAULT NULL COMMENT '权限id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES (1, 1, 1);
INSERT INTO `sys_role_permission` VALUES (2, 1, 5);
INSERT INTO `sys_role_permission` VALUES (3, 1, 6);
INSERT INTO `sys_role_permission` VALUES (4, 1, 7);
INSERT INTO `sys_role_permission` VALUES (5, 1, 8);
INSERT INTO `sys_role_permission` VALUES (6, 2, 1);
INSERT INTO `sys_role_permission` VALUES (7, 2, 2);
INSERT INTO `sys_role_permission` VALUES (8, 2, 3);
INSERT INTO `sys_role_permission` VALUES (9, 2, 4);
INSERT INTO `sys_role_permission` VALUES (10, 1, 2);
INSERT INTO `sys_role_permission` VALUES (11, 1, 3);
INSERT INTO `sys_role_permission` VALUES (12, 1, 4);

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户编号',
  `username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名称',
  `password` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户密码',
  `status` int(1) NOT NULL DEFAULT 1 COMMENT '用户状态(0:关闭、1:开启)',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, 'zhangsan', '1e191d851b3b49a248f4ea62f6b06410', 0);
INSERT INTO `sys_user` VALUES (2, 'lisi', '1e191d851b3b49a248f4ea62f6b06410', 1);
INSERT INTO `sys_user` VALUES (3, 'wangwu', '1e191d851b3b49a248f4ea62f6b06410', 2);
INSERT INTO `sys_user` VALUES (4, 'zhaoliu', '1e191d851b3b49a248f4ea62f6b06410', 3);
INSERT INTO `sys_user` VALUES (5, 'xiaoqi', '1e191d851b3b49a248f4ea62f6b06410', 4);

-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role`  (
  `uid` int(11) NOT NULL COMMENT '用户编号',
  `rid` int(11) NOT NULL COMMENT '角色编号',
  PRIMARY KEY (`uid`, `rid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, 1);
INSERT INTO `sys_user_role` VALUES (1, 3);
INSERT INTO `sys_user_role` VALUES (2, 1);
INSERT INTO `sys_user_role` VALUES (2, 4);
INSERT INTO `sys_user_role` VALUES (3, 1);
INSERT INTO `sys_user_role` VALUES (3, 2);
INSERT INTO `sys_user_role` VALUES (3, 3);
INSERT INTO `sys_user_role` VALUES (3, 4);

SET FOREIGN_KEY_CHECKS = 1;

实体类 User

@Data
public class User implements Serializable {
    private static final long serialVersionUID = 2951987436867980763L;

    /**
     * 主键
     */

    private Long id;
    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private  String password;

    /**
     * 状态
     */
    private Integer status;
}

Role

@Data
public class Role implements Serializable {
    private static final long serialVersionUID = -8250617019976873581L;
    /**
     * 角色id
     */
    private Long id;
    /**
     * 角色名称
     */
    private String name;
    /**
     * 备注
     */
    private String desc;
}

Permission

@Data
public class Permission implements Serializable {
    private static final long serialVersionUID = -3561812452603746297L;

    /**
     * 权限id
     */
    private Long id;
    /**
     * 权限名称
     */
    private String name;
}

mapper包UserMapper

@Repository
public interface UserMapper {


    @Select("select * from sys_user where username =#{username}")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "password",property = "password"),
            @Result(column = "id",property = "roleName",many = @Many(select = "com.lyf.shiro.user.dao.RoleMapper.getByUserId",fetchType = FetchType.EAGER)),
            @Result(column = "id",property = "permissionCodes",many = @Many(select = "com.lyf.shiro.user.dao.PermissionMapper.getByUserId",fetchType = FetchType.EAGER))


    })
    LoginUserVo getByUsername(String username);
}

RolerMapper

@Repository
public interface RoleMapper {



    @Select("select r.name from sys_user_role ur inner join sys_user u on u.id = ur.uid inner join sys_role r on r.id= ur.rid  where uid = #{id}")
   Set<String> getByUserId(Long id);
}

PermissionMapper

@Repository
public interface PermissionMapper {

    @Select("SELECT  p.`name` AS permission_name\n" +
            "FROM `sys_user` u\n" +
            "\n" +
            "INNER JOIN sys_user_role ur  ON u.id = ur.uid\n" +
            "INNER JOIN sys_role  r ON ur.rid = ur.uid\n" +
            "INNER JOIN sys_role_permission rp  ON r.id = rp.role_id\n" +
            "INNER JOIN sys_permission p ON rp.id = p.id\n" +
            "WHERE u.id = #{id}")
    Set<String> getByUserId(Long id);

}

service包下LoginUserService

public interface LoginUserService {


    /**
     * 登录
     * @param username
     * @param password
     * @return
     */
    LoginUserVo login(String username,String password) throws Exception;

    /**
     * 根据用户名
     * @param username
     * @return
     */
    LoginUserVo getByUser(String username);
}

LoginUserServiceImpl

@Service
public class LoginServiceImpl implements LoginUserService {

    @Autowired
    private UserMapper userMapper;
    @Override
    public LoginUserVo login(String username, String password) throws Exception {
        LoginUserVo loginUserVo = getByUser(username);
        //加密密码
        String CodePassword = new Md5Hash(password, "123").toString();
        if (loginUserVo == null) {
            throw new AuthenticationException("用户不存在");
        }
        if (!CodePassword .equals(loginUserVo.getPassword())) {
            throw new AuthenticationException("用户名或密码错误");
        }
        Subject subject = SecurityUtils.getSubject();
        subject.logout();

        if (!subject.isAuthenticated()) {
            try {
                UsernamePasswordToken token = new UsernamePasswordToken(username,password);
                subject.login(token);

            } catch (AuthenticationException e) {
                System.out.println(e.getMessage());
            }
        }
        return loginUserVo;
    }

    @Override
    public LoginUserVo getByUser(String username) {
        return userMapper.getByUsername(username);
    }
}

controller包

package com.lyf.shiro.user.controller;
import com.lyf.shiro.user.service.LoginUserService;
import com.lyf.shiro.user.vo.LoginUserTokenVo;
import com.lyf.shiro.user.vo.LoginUserVo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

@Controller
public class loginController {


    @Autowired
    private LoginUserService loginUserService;
    /**
     * 跳转到登录页面
     * @return
     */
    @RequestMapping("/")
    public String toLogin(){
        return "login";
    }
    /**
     * 登录控制器
     * @param username 用户名
     * @param password 密码
     * @return
     * @throws IOException
     */
    @RequestMapping("/login")
    @ResponseBody
    public Map<String,LoginUserVo> login(String username, String password) throws Exception {
        LoginUserVo login = loginUserService.login(username, password);
        Map<String,LoginUserVo> map = new HashMap<>() ;
        map.put("操作成功",login);
        return map;
    }


    /**
     * 登录成功跳转页面
     * @return
     */
    @RequestMapping("/success")
    public String success(){
        return "success";
    }
    /**
     *无权限页面
     * @return
     */
    @RequestMapping("/noPermission")
    public String noPermiss(){
        return "noPermission";
    }
    /**
     * user/** 下的所有路径
     * @return
     */
    @RequiresPermissions("system:user:add")
    @RequestMapping("/user/add")
    @ResponseBody
    public String user(){
        return "/user/add 添加路径";
    }

    /**
     * 访问admin/** 下所有路径
     * @return
     */
    @RequiresPermissions("system:admin:add")
    @RequestMapping("/admin/add")
    @ResponseBody
    public String admin(){
        return "/admin/add 添加路径";
    }
}

config包

package com.lyf.shiro.config;

import com.lyf.shiro.user.dao.UserMapper;
import com.lyf.shiro.user.vo.LoginUserVo;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashSet;
import java.util.Set;

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserMapper userMapper;
    /**
     * 返回这个域的名称
     * @return
     */

    @Override
    public String getName() {
        super.setName("shiro");
        return super.getName();
    }

    /**
     * 表示是否开启这个域的验证,为true表示开启,为false表示不开启这个域的验证
     * @param token
     * @return
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return true;
    }


    /**
     * 授权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        //获取主要的身份信息这里获取到的是认证SimpleAuthenticationInfo(username,password,getName());传过来的用户名
        //通过用户名去数据库查询角色权限信息,这个做一个简单的角色权限封装
        String username = (String) principals.getPrimaryPrincipal();
        LoginUserVo byUsername = userMapper.getByUsername(username);
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        
        simpleAuthorizationInfo.setRoles(byUsername.getRoleName());
        simpleAuthorizationInfo.setStringPermissions(byUsername.getPermissionCodes());
        return  simpleAuthorizationInfo;
    }
    /**
     * 登录验证需要执行的方法,在主题调用subject.login(token),
     * 具体的验证就会有SecurityManager调用到这个方法进行验证;
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        UsernamePasswordToken  usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        String password = (String) usernamePasswordToken.getCredentials();
        
            //返回验证通过的信息到授权的处理器,授权处理器根据传人的参数设置角色与权限
            return new SimpleAuthenticationInfo(username,password, ByteSource.Util.bytes(token.getCredentials()),getName());

    }
}

ShiroConfig

package com.lyf.shiro.config;

import org.apache.shiro.authc.Authenticator;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.cache.ehcache.EhCache;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
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;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;



@Configuration
public class ShiroConfig {
    
    /**
     * 定义一个默认的安全管理器,这个管理器将管理所有的Shiro组件实例,
     * @param realm 用于访问数据源的域
     * @return
     */
    @Bean
    public SecurityManager securityManager(Realm realm){
        //创建一个默认的实例放入到ioc容器当中
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(realm);
        return  defaultWebSecurityManager;
    }
    /**
     * 定义一个数据源域,这个域Realm需要自己去实现
     * @return
     */
    @Bean
    public MyRealm realm(){
        MyRealm myRealm = new MyRealm();
        //设置缓存管理器
        myRealm.setCacheManager(new EhCacheManager());
        //开启全局缓存
        myRealm.setCachingEnabled(true);
        //开启认证缓存
        myRealm.setAuthenticationCachingEnabled(true);
        //开启授权认证缓存
        myRealm.setAuthorizationCachingEnabled(true);
        return myRealm;
    }

    /**
     * 定义一个过滤器,过滤所有的请求
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        //自定义过滤器
        shiroFilter.setLoginUrl("/");
        shiroFilter.setSuccessUrl("/success");
        shiroFilter.setUnauthorizedUrl("/noPermission");

        Map<String,String> filterMap = new LinkedHashMap<>();
        /**
         /admin/**  表示一个请求名字的通配, 以admin开头的任意子路径下的所有请求
         * anon: 表示该路径不需要进行认证,已访客身份访问
         authc 表示该路径需要进行认证(登录),只有认证(登录)通过才能访问
         ** 表示任意子路径
         *  表示任意的一个路径
         ? 表示 任意的一个字符
         */
        filterMap.put("/login","anon");
       // filterMap.put("admin/**","perms[system:admin:*]");
       // filterMap.put("user/**","perms[system:user:add]");
        //注释表示拦截所有路径的请求,如果换成anon,则放行所有的请求路径
        filterMap.put("/**","authc");
        shiroFilter.setFilterChainDefinitionMap(filterMap);
        return shiroFilter;
    }


    
    //开启注解
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }


    //开启注解
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
 AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
 attributeSourceAdvisor.setSecurityManager(securityManager);
 return attributeSourceAdvisor;
    }
}

配置文件


# 应用名称
spring:
  application:
        name: shiro
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shiro?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      # 链接池初始化大小
      initial-size: 8
      # 最大活跃数
      max-active: 16
      # 最小空闲数
      min-idle: 1
      # 最大等待时间
      max-wait: 60000
mybatis:
  type-aliases-package: com.lyf.shiro.user.domain.* // 换成自己实际的路径
  configuration:
    map-underscore-to-camel-case: true

启动类

@SpringBootApplication
@MapperScan("com.lyf.shiro.user.dao")//换上自己实际的路径
public class ShiroApplication {

    public static void main(String[] args) {

        SpringApplication.run(ShiroApplication.class, args);
    }
}

8.2 测试

账号: zhangsan
密码:123456
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值