springboot项目中使用shiro实现用户登录以及权限的验证

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 这篇文章详细介绍了如何在Spring Boot项目中集成Apache Shiro框架来实现用户登录和权限验证,包括项目依赖配置、数据库连接、实体类定义、控制器、服务层、Mapper层以及前端页面的实现,并展示了实际效果和过滤器代码。

欢迎大家加入我的社区:http://t.csdn.cn/Q52km
社区中不定时发红包


更加高级的验证用户权限:用户表、角色表、权限表。多表联合:https://blog.csdn.net/weixin_43304253/article/details/121124431

1、建立spring boot项目

目录结构这个样子的
在这里插入图片描述


2、项目的jar包依赖

 <dependencies>
        <!--整合shiro
            subject:用户
            security manager:管理所有的用户
            realm:连接数据库

        -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>

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

        <!--整合mybatis-->
        <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <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>
        <!--   JDBC-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!--  Mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>

        <!-- 导入页面依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>    -->

        <!--        thymeleaf,都是基于3.x开发的-->
        <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.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

3、配置文件.properties

#整合mybatis
mybatis.type-aliases-package=com.zheng.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

4、连接数据库的yml文件


thymeleaf:
  prefix: classpath:/templates/  #prefix:指定模板所在的目录
  check-template-location: true  #check-tempate-location: 检查模板路径是否存在
  cache: false  #cache: 是否缓存,开发模式下设置为false,避免改了模板还要重启服务器,线上设置为true,可以提高性能。
  suffix: .html
  encoding: UTF-8
  content-type: text/html
  mode: HTML5



spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/managebook?allowMultiQueries=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    #spring boot 默认是不注入这些属性的,需要自己绑定
    #druid 数据源专有配置
    initiaSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsmMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    filters: stat,wall,log4j
    maxPoolPrepareStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

5、实体类

提示:建议使用Lombok

package com.zheng.pojo;

public class User {
    private String name;
    private String password;
    private String perm;

    public User() {

    }

    public User(String name, String password, String perm) {
        this.name = name;
        this.password = password;
        this.perm = perm;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPerm() {
        return perm;
    }

    public void setPerm(String perm) {
        this.perm = perm;
    }
}

6、controller层

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

@Controller

public class UserController {

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

    //跳转到未授权界面
    @RequestMapping("/ungrant")
    public String ungrant(){
        return "ungrant";
    }

    //跳转到怎加
    @RequestMapping("/admin/add")
    public String addpPage(){
        return "add";
    }

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

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





    @RequestMapping("/login")
    public String login(String username, String password, Model model){
        //获取当前的用户
        Subject subject= SecurityUtils.getSubject();

        //封装用户的登录数据
        UsernamePasswordToken token= new UsernamePasswordToken(username,password);
        try {
            subject.login(token);//执行登陆的方法,如果没有异常则是正确的
            return "index";//进入个人信息界面
        } catch (UnknownAccountException e) {
            model.addAttribute("msg","用户名错误");
            return "login";
        }catch (IncorrectCredentialsException e){
            model.addAttribute("msg","密码不存在");
            return "login";

        }

    }
}

7、service层

package com.zheng.service;

import com.zheng.pojo.User;

public interface UserService {
    //查询用户信息
    User login(String name);

}

8、serviceImpl层

package com.zheng.service.impl;

import com.zheng.mapper.UserMapper;
import com.zheng.pojo.User;
import com.zheng.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;
    @Override
    public User login(String name) {
        return userMapper.login(name);
    }
}

9、mapper层

package com.zheng.mapper;

import com.zheng.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Mapper    //这个注解表示这个是mybatis的mapeper
@Repository
public interface UserMapper {

    //查询用户信息
    User login(String name);

}

10、mapper文件层(编写SQL语句)

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zheng.mapper.UserMapper">

    <!--查询某一个用户的信息-->
    <select id="login" resultType="com.zheng.pojo.User" >
        select  * from user where name=#{name}
    </select>

</mapper>

11、前端页面简单的表示(这里制作简单的演示、前端框架也很多)

11.1、index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>

<a th:href="@{/admin/add}">add</a>&nbsp;&nbsp;&nbsp;&nbsp;<a th:href="@{/admin/update}">update</a>

</body>
</html>

11.2、login.htm

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>

<form th:action="@{/login}" >
    用户名:<input type="text" name="username" placeholder="请输入姓名" ><br>
    密码:<input type="text" name="password" placeholder="请输入密码"> <br>
    <button type="submit" >登录</button>
</form>

</body>
</html>

11.3、ungrant.html未授权页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>未授权页面</title>
</head>
<body>
未授权页面
</body>
</html>

11.4、add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>增加页面</title>
</head>
<body>
add
</body>
</html>

11.5、update.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改页面</title>
</head>
<body>
update
</body>
</html>

12、实际效果展示

12.1、第一种情况、还未登录直接访问首页中的链接

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


12.2、第二种情况、登录后访问首页中的链接

首先看一下数据库中数据、更加具有说服力
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在首页中测试add
在这里插入图片描述
在首页中测试update
在这里插入图片描述


13、解析说明 、过滤器的代码

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

@Configuration
public class ShiroConfig {
    //ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securitymanager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        //添加shiro的内置过滤器
        /**
         *  anon:无需认证就可访问  *  authc:必须认证才能访问*  User:必须拥有 记住我 功能才能用
         *  perms:拥有对某个资源的权限才能访问*  role:拥有某个角色权限才能访问
         */
        Map<String, String> filterMap = new LinkedHashMap<>();
        //授权,正常的情况下,没有授权会跳转到未授权页面
//        filterMap.put("/admin/*","authc");//admin请求下的都需要认证
        filterMap.put("/admin/add", "perms[user:add]");
        filterMap.put("/admin/update", "perms[user:update]");

        bean.setFilterChainDefinitionMap(filterMap);
        //如果没有认证、设置登录的请求
        bean.setLoginUrl("/toLogin");
        //如果没有授权,跳转到未收取页面
        bean.setUnauthorizedUrl("/ungrant");
        return bean;

    }

    //DefaultWebSecurityManager
    @Bean(name = "securitymanager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securitymanager = new DefaultWebSecurityManager();
        //关联UserRealm
        securitymanager.setRealm(userRealm);
        return securitymanager;

    }

    //创建realm对象,需要自定义安装
    @Bean
    public UserRealm userRealm() {

        return new UserRealm();
    }

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

}

14、授权和认证

package com.zheng.config;

import com.zheng.pojo.User;
import com.zheng.service.UserService;
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;

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

//自定义的UserRealm

public class UserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        System.out.println("执行了授权");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//        info.addStringPermission("user:update");

        //拿到当前的登录对象
        Subject subject = SecurityUtils.getSubject();
        User user = (User)subject.getPrincipal();

        //设置当前用户的权限
        info.addStringPermission(user.getPerm());

        return info;

    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 第一种方式
        // 获取用户输入的账号和密码(一般只需要获取账号就可以)
        System.out.println("执行了认证");
        UsernamePasswordToken userToken = (UsernamePasswordToken) token;
        //连接真实的数据库

        User user = userService.login(userToken.getUsername());

        //1、思路:在用户表中新增加一个权限字段、然后再次查询数据库获得该用户所具有的权限(该权限为要给集合??????
        if(user == null){
            //没有这个人
            return null;
        }
        //密码认证
        return  new SimpleAuthenticationInfo(user,user.getPassword(),"");

    }
}

15、关键解说:

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

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
Java 容器
如何在SpringBoot项目中使用过滤器和拦截器
过滤器和拦截器是日常开发中常用技术,用于对特定请求进行增强处理,如插入自定义代码以实现特定功能。过滤器在请求到达 `servlet` 前执行,而拦截器在请求到达 `servlet` 后执行。`SpringBoot` 中的拦截器依赖于 `SpringBoot` 容器,过滤器则由 `servlet` 提供。通过实现 `Filter` 接口并重写 `doFilter()` 方法可实现过滤器;通过实现 `HandlerInterceptor` 接口并重写相应方法可实现拦截器。两者的主要区别在于执行时机的不同,需根据具体场景选择使用。
如何在SpringBoot项目中使用过滤器和拦截器
|
8天前
|
安全 Java Apache
SpringBoot+Shiro(一)
SpringBoot+Shiro(一)
|
9天前
|
前端开发 JavaScript Java
SpringBoot项目部署打包好的React、Vue项目刷新报错404
本文讨论了在SpringBoot项目中部署React或Vue打包好的前端项目时,刷新页面导致404错误的问题,并提供了两种解决方案:一是在SpringBoot启动类中配置错误页面重定向到index.html,二是将前端路由改为hash模式以避免刷新问题。
49 1
|
25天前
|
Java 关系型数据库 MySQL
创建一个SpringBoot项目,实现简单的CRUD功能和分页查询
【9月更文挑战第6天】该内容介绍如何使用 Spring Boot 实现具备 CRUD 功能及分页查询的项目。首先通过 Spring Initializr 创建项目并选择所需依赖;其次配置数据库连接,并创建实体类与数据访问层;接着构建服务层处理业务逻辑;最后创建控制器处理 HTTP 请求。分页查询可通过添加 URL 参数实现。
|
7天前
|
JavaScript Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
本文介绍了一个基于Spring Boot和Vue.js实现的在线考试系统。随着在线教育的发展,在线考试系统的重要性日益凸显。该系统不仅能提高教学效率,减轻教师负担,还为学生提供了灵活便捷的考试方式。技术栈包括Spring Boot、Vue.js、Element-UI等,支持多种角色登录,具备考试管理、题库管理、成绩查询等功能。系统采用前后端分离架构,具备高性能和扩展性,未来可进一步优化并引入AI技术提升智能化水平。
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
|
9天前
|
Java 关系型数据库 MySQL
毕设项目&课程设计&毕设项目:springboot+jsp实现的房屋租租赁系统(含教程&源码&数据库数据)
本文介绍了一款基于Spring Boot和JSP技术的房屋租赁系统,旨在通过自动化和信息化手段提升房屋管理效率,优化租户体验。系统采用JDK 1.8、Maven 3.6、MySQL 8.0、JSP、Layui和Spring Boot 2.0等技术栈,实现了高效的房源管理和便捷的租户服务。通过该系统,房东可以轻松管理房源,租户可以快速找到合适的住所,双方都能享受数字化带来的便利。未来,系统将持续优化升级,提供更多完善的服务。
毕设项目&课程设计&毕设项目:springboot+jsp实现的房屋租租赁系统(含教程&源码&数据库数据)
|
20小时前
|
Java 关系型数据库 数据库连接
SpringBoot项目使用yml文件链接数据库异常
【10月更文挑战第3天】Spring Boot项目中数据库连接问题可能源于配置错误或依赖缺失。YAML配置文件的格式不正确,如缩进错误,会导致解析失败;而数据库驱动不匹配、连接字符串或认证信息错误同样引发连接异常。解决方法包括检查并修正YAML格式,确认配置属性无误,以及添加正确的数据库驱动依赖。利用日志记录和异常信息分析可辅助问题排查。
22 10
|
5天前
|
JavaScript 前端开发 Java
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
18 6
|
6天前
|
消息中间件 Java Kafka
springboot项目启动报错-案例情景介绍
springboot项目启动报错-案例情景介绍
15 2
|
2月前
|
小程序 前端开发 Java
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
JavaDog Chat v1.0.0 是一款基于 SpringBoot、MybatisPlus 和 uniapp 的简易聊天软件,兼容 H5、小程序和 APP,提供丰富的注释和简洁代码,适合初学者。主要功能包括登录注册、消息发送、好友管理及群组交流。
60 0
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
下一篇
无影云桌面