前言:

本文内容:SpringBoot整合Shiro环境搭建、Shiro实现登录拦截、Shiro实现用户认证

推荐免费SpringBoot基础教程视频:【狂神说Java】SpringBoot最新教程通俗易懂_哔哩哔哩_bilibili

SpringBoot整合Shiro环境搭建

  1. 新建springboot-07-shiro项目并勾选Spring Web

  2. 引入thymleaf依赖和Shiro依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!--        thymeleaf-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <!-- shiro-->
    <dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.9.0</version>
    </dependency>
  3. controller包下新建IndexController

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package com.jokerdig.controller;

    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;

    /**
    * @author Joker大雄
    * @data 2022/7/26 - 11:04
    **/
    @Controller
    public class IndexController {

    @RequestMapping({"/","/index"})
    public String index(Model model){
    model.addAttribute("msg","hello shiro");
    return "index";
    }
    }
  4. templates下新建index.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
    <meta charset="UTF-8">
    <title>首页</title>
    </head>
    <body>
    <h1>首页</h1>
    <p th:text="${msg}"></p>
    </body>
    </html>
  5. config包下新建ShiroConfigUserRealm

    ShiroConfig

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    package com.jokerdig.config;

    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;

    /**
    * @author Joker大雄
    * @data 2022/7/26 - 11:04
    **/
    @Configuration
    public class ShiroConfig {

    // ShiroFileFactoryBean
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
    ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
    //设置安全管理器
    bean.setSecurityManager(defaultWebSecurityManager);
    return bean;
    }

    // DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    // 关联UserRealm
    securityManager.setRealm(userRealm);
    return securityManager;
    }
    // 创建Realm 对象 需要自定义
    @Bean
    public UserRealm userRealm(){
    return new UserRealm();
    }
    }

    UserRealm

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package com.jokerdig.config;

    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;

    /**
    * @author Joker大雄
    * @data 2022/7/26 - 11:12
    **/
    // 自定以 Realm extends AuthorizingRealm
    public class UserRealm extends AuthorizingRealm {
    // 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    System.out.println("执行了授权");

    return null;
    }

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

    return null;
    }
    }
  6. templates/user下新建html页面来测试

    add.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    <h1>add</h1>
    </body>
    </html>

    update.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    <h1>update</h1>
    </body>
    </html>
  7. IndexController下新建测试方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    package com.jokerdig.controller;

    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;

    /**
    * @author Joker大雄
    * @data 2022/7/26 - 11:04
    **/
    @Controller
    public class IndexController {

    // 首页
    @RequestMapping({"/","/index"})
    public String index(Model model){
    model.addAttribute("msg","hello shiro");
    return "index";
    }
    // add
    @RequestMapping("/user/add")
    public String add(){

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

    return "/user/update";
    }
    }
  8. templates下的index.html添加跳转

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
    <meta charset="UTF-8">
    <title>首页</title>
    </head>
    <body>
    <h1>首页</h1>
    <p th:text="${msg}"></p>
    <hr>
    <a th:href="@{/user/add}">add</a> | <a th:href="@{/user/update}">update</a>
    </body>
    </html>
  9. 测试环境搭建完成

Shiro实现登录拦截

  1. ShiroConfig中的shiroFilterFactoryBean方法下添加过滤器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // ShiroFileFactoryBean
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") 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");

    bean.setFilterChainDefinitionMap(filterMap);
    // 设置登录请求
    bean.setLoginUrl("/toLogin");
    return bean;
    }
  2. templates下新建login.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
    <meta charset="UTF-8">
    <title>登录</title>
    </head>
    <body>
    <p th:text="${msg}" style="color: red"></p>
    <form th:action="@{/login}">
    <p>用户名:</p><input type="text" name="username">
    <p>密码:</p><input type="password" name="password">
    <p><input type="submit"></p>
    </form>
    </body>
    </html>
  3. IndexController下添加去登录方法

    1
    2
    3
    4
    5
    //toLogin
    @RequestMapping("/toLogin")
    public String toLogin(){
    return "login";
    }
  4. 运行测试

    点击首页的addupdate会跳转到登录页面,拦截成功

Shiro实现用户认证

  1. IndexController下添加登录方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // login
    @RequestMapping("/login")
    public String login(String username,String password,Model model){
    // 获取当前用户
    Subject subject = SecurityUtils.getSubject();
    // 封装用户的登录数据
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    // 登录使用token
    try {
    subject.login(token);
    // 简单异常捕获
    } catch (UnknownAccountException e) {
    model.addAttribute("msg","用户名不存在");
    return "login";
    } catch (IncorrectCredentialsException e){
    model.addAttribute("msg","密码错误");
    return "login";
    }
    return "redirect:index";
    }
  2. UserRealm中设置用户认证

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    System.out.println("执行了认证");
    // 用户名 密码 从数据库取 这里暂时为测试数据
    String username = "root";
    String password = "123456";

    UsernamePasswordToken userToken = (UsernamePasswordToken) token;
    if(!userToken.getUsername().equals(username)){
    return null; //抛出异常 UnknownAccountException
    }
    // 密码认证 shiro来做
    return new SimpleAuthenticationInfo("",password,"");

    }
  3. 运行测试

    账号和密码输入错误都有对应的提示,成功登录后可以访问addupdate页面