使用springboot整合shiro进行登录认证(md5+盐值+散列次数)

准备工作:
md5加密算法:

public class md5Test {
    @Test
    public void md5() {
        //明文(123) + 盐值(monian) + 加密次数(1024)    ==>  密文  8ea680082c12d7d878a3a97214ebbdc2
        Md5Hash md5Hash = new Md5Hash("123","monian",1024);
        System.out.println(md5Hash);
    }
}

创建Springboot项目web、Lombok:

由于我们使用的是jsp,需要引入相关的依赖(防止访问页面时,访问的是资源路径(访问后不解析,会直接下载文件))

此外还有shiro依赖、mybatis-plus、mysql、druid:

 <!--jsp-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <!--shiro-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.5.3</version>
        </dependency>
<!--    mybatis-plus    -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
<!--    mysql    -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
<!--    druid    -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>

properties.yml配置文件: 

server:
  port: 8080
  servlet:
    context-path: /shiro
spring:
  mvc:
    view:
      prefix: /
      suffix: .jsp
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    password: chen
    username: root
    url: jdbc:mysql://localhost:3306/shiro?useSSL=false&userUnicode=true&characterEncoding=utf8
    druid:
      max-active: 10
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  type-aliases-package: net.wanho.entity
  mapper-locations: classpath:mapper/*.xml

创建Realm(数据源)对象:

/**
 * 自定义Realm ,继承AuthorizingRealm
 */
public class ShiroRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;

    /**
     * 认证
     * Authentication 证明真实性,鉴定;身份验证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //先怼死 不要从数据库找数据 admin 123
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
        //用户输入用户名
        String username = usernamePasswordToken.getUsername();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        User user = userService.getOne(wrapper);
        //账号不存在
        if(ObjectUtils.isEmpty(user)){
            throw new UnknownAccountException("账号不存在!!!");
        }

//        String password = (String) usernamePasswordToken.getCredentials();
//        if (!password.equals("8ea680082c12d7d878a3a97214ebbdc2")){
//            throw new IncorrectCredentialsException("账号密码错误!!!");
//        }

        //密文密码
        //存放盐值
        ByteSource byteSource = ByteSource.Util.bytes(user.getSalt());
        return new SimpleAuthenticationInfo(username,user.getPassword(),byteSource,super.getName());
    }

    /**
     * 授权
     * Authorization 批准书,授权书;批准
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}

添加shiro的配置:

@Configuration
public class ShiroConfig {

    /**
     *  获得认证的数据源
     *  realm 领域、范围
     *  @return
     */
    @Bean
    public Realm getRealm() {
        ShiroRealm realm = new ShiroRealm();
        //使用 md5 加密
        //创建密码匹配器,支持散列算法
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5"); //设置加密算法
        credentialsMatcher.setHashIterations(1024); //设置散列次数
        //设置密码匹配器
        realm.setCredentialsMatcher(credentialsMatcher);
        return realm;
    }

    /**
     * 创建安全管理器 类似于: 自定义XXService
     * 自定义的Realm交给SecurityManager管理
     * @param realm
     * @return
     */
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
        return securityManager;
    }

    /**
     * ShiroFilter ,对资源进行过滤处理
     * 将SecurityManager交给ShiroFilterFactoryBean管理
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        //设置过滤路径 anon 默认 authc 认证 roles perms 授权 logout 退出
        Map<String,String> map = new LinkedHashMap<>();
        map.put("/index.jsp","authc");
        map.put("/login.jsp","anon");
        //设置安全管理器
        filterFactoryBean.setSecurityManager(securityManager);
        filterFactoryBean.setFilterChainDefinitionMap(map);
        filterFactoryBean.setLoginUrl("/login.jsp");
        return filterFactoryBean;
    }
}

配置mybatis-plus的配置:

/**
 * 配置类: 类似于 spring => *.xml
 */
@Configuration
@MapperScan("net.wanho.mapper")
public class MybatisPlusConfig {
    /**
     * 配置拦截器
     * @return
     */
    @Bean
    public MybatisPlusInterceptor configMybatisPlusInterceptor(){
        //创建拦截器实例
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //添加 分页拦截器 指定数据库
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

添加实体:

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User implements Serializable {
    private Integer id;
    private String username;
    private String password;
    private String salt;
}

mapper:

public interface UserMapper extends BaseMapper<User> {
    User selectUsernameAndPassword(String username);
}

service:

public interface UserService extends IService<User> {
}
@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

controller:

@Controller
@RequestMapping("/user")
public class UserController {

    @PostMapping("/login")
    public String login(String username, String password, Model model){
        try {
            //获得用户主体
            Subject subject = SecurityUtils.getSubject();
            //封装 token
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            //调用登录
            subject.login(token);
            //subject.checkPermission("user:view");
            //跳转到主页
            return "index";
        } catch (Exception e) {
            //设置错误消息
            model.addAttribute("msg","账号或密码错误!!!") ;
            //跳到到登录页面
            return "login";
        }
    }

    @GetMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "redirect:/login.jsp";
    }
}

注意注解!!!,不能使用@RestController,返回的是json/xml文件,不会进行解析;

前端界面:

index.jsp:

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<%@page contentType="text/html;UTF-8" pageEncoding="UTF-8" isErrorPage="false" %>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<%--受限资源--%>
<h1>系统主页</h1>
<h2>欢迎: <shiro:principal/> </h2>
<a href="${pageContext.request.contextPath}/user/logout">安全退出</a>
<h1>系统主页</h1>

<ul>
    <li><a href="#">用户管理</a></li>
    <li><a href="#">商品管理</a></li>
    <li><a href="#">订单管理</a></li>
    <li><a href="#">物流管理</a></li>
</ul>
</body>
</html>

 login.jsp:

<%@page contentType="text/html;UTF-8" pageEncoding="UTF-8" isErrorPage="false" isELIgnored="false" %>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<style>
    .massage{
     color: red;
    }
</style>
<body>
<h1>登录界面</h1>
<a href="${pageContext.request.contextPath}/user/logout">安全退出</a>
<form action="${pageContext.request.contextPath}/user/login" method="post">
    用户名:<input type="text" name="username" > <br/>
    密码:<input type="password" name="password"> <br>
    <input type="submit" value="登录">
</form>
<hr>
<h4 class="massage">${msg}</h4>
</body>
</html>

浏览器测试: 

  

当点击安全退出按钮,默认返回的是login.jsp界面,再次输入index.jsp,也会跳到登陆界面 

知识点梳理:
Spring MVC中内嵌9大成员,使用model可以将数据带到前端界面

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/540043.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥杯嵌入式】串口通信与RTC时钟

【蓝桥杯嵌入式】串口通信与RTC时钟 串口通信cubemx配置串口通信程序设计 RTC时钟cubemx配置程序设计 串口通信 cubemx配置 打开串口通信&#xff0c;并配置波特率为9600 打开串口中断 重定义串口接收与发送引脚&#xff0c;默认是PC4&#xff0c;PC5&#xff0c;需要改为P…

vue3 依赖-组件tablepage-vue3说明文档,列表页快速开发,使用思路及范例(Ⅳ)其他配置项

vue3 依赖-组件tablepage-vue3说明文档&#xff0c;列表页快速开发&#xff0c;使用思路及范例&#xff08;Ⅰ&#xff09;配置项文档 vue3 依赖-组件tablepage-vue3说明文档&#xff0c;列表页快速开发&#xff0c;使用思路及范例&#xff08;Ⅱ&#xff09;搜索及数据获取配…

STL函数对象

1&#xff0c;函数对象 1.1 函数对象概念 概念&#xff1a; 重载函数调用操作符的类&#xff0c;其对象常称为函数对象函数对象使用重载的&#xff08;&#xff09;时&#xff0c;行为类似函数调用&#xff0c;也称为仿函数 本质&#xff1a; 函数对象&#xff08;仿函数&…

国外站群服务器有哪几种?

国外站群服务器种类繁多&#xff0c;它们各具特色&#xff0c;适用于不同的业务需求和场景。以下将为您科普几种常见的国外站群服务器及其特点。 首先&#xff0c;美国站群服务器以其丰富的IP资源和强大的网络技术著称。作为全球网络技术和数据中心发展的领先者&#xff0c;美国…

僵尸进程和孤儿进程

目录 引言僵尸进程僵尸进程的状态僵尸进程周边知识 孤儿进程孤儿进程的状态 进程中的其他状态①.R---表示进程运行状态。②.S---表示进程的休眠状态。(进程什么都没做)③T 和 t 进程的运行、阻塞和挂起运行阻塞挂起状态&#xff1a; 引言 今天我们来将僵尸进程和孤儿进程以及其…

matlab使用教程(42)—常见的二维图像绘制方法

这个博客用于演示如何在 MATLAB 中创建曲线图、条形图、阶梯图、误差条形图、极坐标图、针状图、散点图。 1.曲线图 plot 函数用来创建 x 和 y 值的简单线图。 x 0:0.05:5; y sin(x.^2); figure plot(x,y) 运行结果&#xff1a; 线图可显示多组 x 和 y 数据。 x 0:0.05:…

如何正确使用数字化仪前端信号调理?(二)

在上期文章如何正确使用数字化仪前端信号调理&#xff1f;&#xff08;一&#xff09;中&#xff0c;我们为大家介绍了数字化仪前端电路所需的特性以及使用过程中需要的输入抗阻和输入耦合&#xff0c;本期文章将为您介绍数字化仪前端信号调理的使用过程中所需的输入电压范围&a…

一键开启Scrum回顾会议的精彩时刻

其实回顾会议作为一个检视、反馈、改进环节&#xff0c;不仅在传统的瀑布管理模式中&#xff0c;还是在Scrum一类的敏捷管理流程中&#xff0c;都是非常重要的活动。一些团队认为它无法产生直接的价值&#xff0c;所以有意忽略了这个会议&#xff1b;一些团队在越来越多的回顾中…

bilibili PC客户端架构设计——基于Electron

众所周知&#xff0c;bilibili是个学习的网站&#xff0c;网页端和粉版移动端都非常的好用&#xff0c;不过&#xff0c;相对其它平台来说bilibili的PC客户端也算是大器晚成了。在有些场景PC客户端的优势也是显而易见的&#xff0c;比如&#xff0c;跓留电脑桌面的快捷、独立的…

Redis搭建主从

Redis搭建主从: 1:拉取Redis镜像 docker pull redis2:创建主从对应的目录结构 3:对redis6379.log,redis6380.log,redis6381.log进行授权 chmod 777 redis6379.log chmod 777 redis6380.log chmod 777 redis6381.log4:修改主(master)的配置文件 5:创建主(master) redis_6379 …

二维数组---刷题

一维数组不想更了&#xff0c;弄点二维数组&#xff01; 1.对角线 已知一个6*6的矩阵&#xff0c;把矩阵两条对角线上的元素加上10&#xff0c;然后输出这个新矩阵。 思路 题目简单&#xff0c;6*636&#xff0c;可以得知有36个元素。数组就定义成a[7][7]&#xff0c;难点在与…

最前沿・量子退火建模方法(1) : subQUBO讲解和python实现

前言 量子退火机在小规模问题上的效果得到了有效验证&#xff0c;但是由于物理量子比特的大规模制备以及噪声的影响&#xff0c;还没有办法再大规模的场景下应用。 这时候就需要我们思考&#xff0c;如何通过软件的方法怎么样把大的问题分解成小的问题&#xff0c;以便通过现在…

哪些因素影响阻抗控制?网格铜的妙用

原文来自微信公众号&#xff1a;工程师看海&#xff0c;与我联系&#xff1a;chunhou0820 看海原创视频教程&#xff1a;《运放秘籍》 大家好&#xff0c;我是工程师看海&#xff0c;原创文章欢迎点赞分享&#xff01; 前文介绍了传输线、特性阻抗以及信号的反射概念&#xff…

【漏洞复现】用友 NC PaWfm SQL注入漏洞

0x01 产品简介 用友NC是用友网络科技股份有限公司开发的一款大型企业数字化平台。它主要用于企业的财务核算、成本管理、资金管理、固定资产管理、应收应付管理等方面的工作&#xff0c;致力于帮助企业建立科学的财务管理体系&#xff0c;提高财务核算的准确性和效率。 0x02 …

在线批量生成URL HTML单页网页程序

输入前缀、开始数字、结束数字、后缀 即可快速生成 几万、十万、百万 条链接。 支持 一键复制、 一键导出本地 txt 文件。 源码免费下载地址抄笔记 (chaobiji.cn)

Spring MVC应用分层(三层架构)

该片文章主要是对 Spring MVC应用分层&#xff08;三层架构&#xff09;进行简单的介绍和学习。 一、介绍 1、什么是应用分层 应用分层 是一种 软件开发设计思想 , 它将应用程序分成N个层次, 这N个层次分别负责各自的职责, 多个 层次之间协同提供完整的功能. 根据项目的复杂…

正则表达式:量词(三)

正则表达式中的量词有以下几种:1. *: 匹配前面的字符0次或多次。2. : 匹配前面的字符1次或多次。3.?: 匹配前面的字符0次或1次。4. {n}: 匹配前面的字符恰好n次。5. {n,}: 匹配前面的字符至少n次。6. {n,m}:匹配前面的字符至少n次&#xff0c;但不超过m次。 以下是使用Python的…

0.1 + 0.2 不等于 0.3 ?这是为什么?一篇讲清楚!!!

0.1 0.2 不等于 0.3 &#xff1f;这是为什么&#xff1f;一篇讲清楚&#xff01;&#xff01;&#xff01; 分类 编程技术 在很多编程语言中&#xff0c;我们都会发现一个奇怪的现象&#xff0c;就是计算 0.1 0.2&#xff0c;它得到的结果并不是 0.3&#xff0c;比如 C、C、…

C语言--结构体大小

基本数据类型占用的字节数分别为:char(1),short(2),int(4),long(4),long long(8),float(4),double(8)。 分析一下下面结构体占用的字节数。 struct A { int a; }; struct B { char a; int b; }; int main() { printf("sizeof(struct A)%d\n", sizeof(struct A));//测…

云计算:OVS 集群 使用 Geneve 流表

目录 一、实验 1.环境 2.OVS 集群 使用 Geneve 流表 二、问题 1.VXLAN与Geneve区别 一、实验 1.环境 (1) 主机 表1 宿主机 主机架构软件IP网卡备注ovs_controller控制端 karaf 0.7.3 192.168.204.63 1个NAT网卡 &#xff08;204网段&#xff09; 已部署ovs_server01服务…