Java安全框架(课时二十三)笔记内容十三

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用版 2核4GB 50GB
简介: Java安全框架(课时二十三)笔记内容十三

本案例实战框架用了以下技术

  • SpringBoot框架
  • Shiro的框架
  • MyBatis框架
  • Spring框架
  • thymeleaf技术
  • SSM三层框架
  • 数据库

实操部分

Subject——org.apache.shiro.subject.Subject


特定于当前与软件交互的实体的安全视图


SecurityManager——org.apache.shiro.mgt.SecurityManager


Shiro架构的核心,管理并协调各个组件共同完成安全工作,它还管理每个应用程序用户的Shiro视图,因此它知道如何为每个用户执行安全操作。


Authenticator——org.apache.shiro.authc.Authenticator


Authenticator是负责认证的组件,当用户尝试登录时,登录是由Authenticator来执行的,Authenticator将会从Realms取出用户信息,来和用户提供的登录信息进行比对


Authenticator Strategy——org.apache.shiro.authc.pam.AuthenticationStrategy


如果超过一个Realm被配置了,这个AuthenticationStrategy将会协调这些Realms来决定认证操作是否成功,比如,认证成功是需要所有的Realms都认证成功,还是仅仅一个Realm成功


Authorizer——org.apache.shiro.authz.Authorizer


Authorizer是负责访问控制的组件,换句话说,它负责检测用户是否有执行某个操作的权限。和Authenticator一样,Authorizer也从多个Realms数据源中获取用户的角色信息和权限信息,通过这些信息来判断用户是否可以执行某个操作


SessionManager——org.apache.shiro.session.mgt.SessionManager


注意不是SecurityManager,SessionManager负责创建和管理用户的Session周期。在安全框架中,Shiro提供了一个独有的特性,Shiro可以在任何环境中管理用户会话,即使实在非Web/Servlet和非EJB容器环境中,默认情况下,Shiro将会使用已有的会话机制,如Servlet容器,如果没有,Shiro将会使用内建的企业会话管理机制来管理会话。通过SessionDao,我们可以使用任何数据源来持久化Session


SessionDAO——org.apache.shiro.session.mgt.eis.SessionDAO


SessionDAO代表SessionManager执行会话持久性(CRUD)操作。它允许将任何数据存储插入到Session Management基础结构中


CacheManager——org.apache.shiro.cache.CacheManager


CacheManager负责创建Shiro中的其他组件的Cache实例并管理其生命周期,因为Shiro需要访问各种数据源来进行认证,授权和会话管理,缓存一直是框架中的一流架构特性,可以在使用这些数据源时提高性能,任何现代的开源或者企业缓存产品都可以接入Shiro中


Cryptography——org.apache.shiro.crypto.*


Shiro的crypto包包含了易于使用和理解的常见加密算法实现。使用过Java自带的加密库的人都应该知道它很难使用,Shiro提供的加密API简化了复杂的Java机制,让加密更便于使用


Realms——org.apache.shiro.realm.Realm


正如前面提到的,Realms是Shiro和应用程序数据的桥梁,当需要执行认证和授权时,Shiro会从至少一个Realm中寻找用户信息,应用程序中可以配置许多个Realm,Shiro会在必要时协调这些Realm

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.7.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lop</groupId>
    <artifactId>shiro-springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shiro-springboot</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--        mybatis整合SpringBoot-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <!--整合包-->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
        <!--   druids数据源    -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.12</version>
        </dependency>
        <!--    log4j    -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>
        <!--        MySql的依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.9.1</version>
        </dependency>
        <!--        Thymeleaf模板-->
        <!--Thymeleaf  说明基于3.0.1 模板引擎-->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-java8time</artifactId>
            <version>3.0.4.RELEASE</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>
        <dependency>
            <groupId>org.xmlunit</groupId>
            <artifactId>xmlunit-core</artifactId>
            <version>2.5.1</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Yml文件信息

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    initial-size: 5
    min-idle: 5
    max-active: 20
    # 配置获取连接等待超时的时间
    max-wait: 60000
    # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
    time-between-eviction-runs-millis: 60000
    # 配置一个连接在池中最小生存的时间,单位是毫秒
    min-evictable-idle-time-millis: 300000
    validation-query: SELECT 1 FROM DUAL
    test-while-idle: true
    test-on-borrow: false
    test-on-return: false
    # 打开PSCache,并且指定每个连接上PSCache的大小
    pool-prepared-statements: true
    #   配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 最好的功能
    max-pool-prepared-statement-per-connection-size: 20
    filters: stat,wall
    use-global-data-source-stat: true
    # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
    connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

index.html页面

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http:www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<div shiro:hasPermisssion="user:add">
    假如hasPermisssion有这个限制
    <a th:href="@{/user/add}">add</a>
</div>
<div align="center">
    <h1>index</h1>
    <!--/*@thymesVar id="msg" type="java"*/-->
    <p th:text="${msg}"></p>
    <a th:href="@{/user/add}">add</a>
    <br>
    <a th:href="@{/user/update}">update</a>
</div>
</body>
</html>

login.html页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--从Session判断值-->
<div align="center"  th:if="session.loginUser==null">
    <h1>登录</h1>
    <hr>
    <!--/*@thymesVar id="msg" type="java"*/-->
    <h2 th:text="${msg}" style="color: red;"></h2>
    <form  th:action="@{/login}" method="post">
        <p>用户名:<input type="text" name="username" placeholder="请输入用户名"></p>
        <p>用户密码:<input type="password" name="password" placeholder="请输入用户密码"></p>
        <p><input type="submit"></p>
    </form>
</div>
</body>
</html>

add.html

 

update.html

数据层:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--比要时候要加上-->
<!--suppress ALL -->
<mapper namespace="com.lop.mapper.UserMapper">
    <select id="queryUserByName" parameterType="String" resultType="User">
        select * from  mybatis.user where  name =#{name}
    </select>
</mapper>
package com.lop.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Repository
@Mapper
public interface UserMapper {
    public UserMapper queryUserByName(String username);
}

Service层:

package com.lop.Service;
import com.lop.pojo.User;
public interface UserService {
    public User queryUserByName(String username);
}

package com.lop.Service;
import com.lop.mapper.UserMapper;
import com.lop.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceLmp implements UserService {
    @Autowired
    UserMapper userMapper;
    @Override
    public User queryUserByName(String username) {
        userMapper.queryUserByName(username);
        return null;
    }
}

控制层:

package com.lop.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.session.Session;
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 MyController {
    @RequestMapping({"/", "/index"})
    public String toIndex(Model model) {
        model.addAttribute("msg", "hllow");
        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 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";
        }
    }
    @RequestMapping("/noauth")
    public  String unauthorized(){
        return "没有授权无法访问信息";
    }
}

认证授权

package com.lop.config;
import com.lop.Service.UserService;
import com.lop.pojo.User;
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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
/**
 * 自定义的UserRealm
 */
public class UserRealm extends AuthorizingRealm {
    //把用户数据库拿过来 连接真实数据库
    @Autowired
    UserService  userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("----------------------授权");
        //  SimpleAuthorizationInfo
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //打开没有授权的功能
        info.addStringPermission("uder:add");
        //拿到当前对象
        Subject subject = SecurityUtils.getSubject();
        User  currentUser = (User) subject.getPrincipal();//拿到user对象
        //设置当前用户的权限
        info.addStringPermission(currentUser.getPerms());
        return info;
    }

  //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("==========================认证");
    //        String name = "root";
    //        String password = "123456";
        UsernamePasswordToken usertoken = (UsernamePasswordToken) token;
        //连接真实数据库
       User user=userService.queryUserByName(usertoken.getUsername());
         if (user == null) {
             return null;
         }
        Subject cursubject = SecurityUtils.getSubject();
        Session session = cursubject.getSession();
        session.setAttribute("loginUser",user);
        //        if(!usertoken.getUsername().equals(name)){
    //            return null;
    //        }
        //密码认证
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }

ShiroConfig 代码解读:

package com.lop.config;
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.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
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);

  //授权的信息内容 有user:add 没有授权
        filterMap.put("/user/add", "perms[user:add]");
        filterMap.put("/user/update", "perms[user:update]");
 //用户没有授权请前往这个页面
        bean.setLoginUrl("/noauth");

 //设置登录请求
        bean.setLoginUrl("/tologin");
        bean.setFilterChainDefinitionMap(filterMap);
        return bean;
    }

 // 自定义的UserRealm
    //    @Bean(name = "userRealm")
    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }

<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http:www.thymeleaf.org/thymeleaf-extras-shiro">

<div shiro:hasPermisssion="user:add">
    假如hasPermisssion有这个限制
    <a th:href="@{/user/add}">add</a>
</div>

<div align="center">
    <h1>index</h1>
    <!--/*@thymesVar id="msg" type="java"*/-->
    <p th:text="${msg}"></p>
    <a th:href="@{/user/add}">add</a>
    <br>
    <a th:href="@{/user/update}">update</a>
</div>

login的登录

 

SpringBoot

理论介绍:

//设置管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        //增加shiro的内置过滤器
        /**
         * anon
         * authc
         * perms
         * role
         */
        Map<String, String> filterMap = new LinkedHashMap<>();
//        filterMap.put("/user/add","authc");
//        filterMap.put("/user/update","authc");
        filterMap.put("/user/*", "authc");
        //授权的信息内容 有user:add 没有授权
        filterMap.put("/user/add", "perms[user:add]");
        filterMap.put("/user/update", "perms[user:update]");
        //用户没有授权请前往这个页面
        bean.setLoginUrl("/noauth");
        //设置登录请求
        bean.setLoginUrl("/tologin");
        bean.setFilterChainDefinitionMap(filterMap);
        return bean;
    }

    //DefaultWebSecurityManager
    //DefaultWebSecurityManager 管理
    @Bean("securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    // 自定义的UserRealm
    //    @Bean(name = "userRealm")
    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }

    /*整合包 thymeleaf-extras-shiro */
    @Bean
    public  SiroDialect getSiroDialect() {
        return new SiroDialect();
    }

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
5天前
|
安全 Java 网络安全
Java Socket编程教程:构建安全可靠的客户端-服务器通信
【6月更文挑战第21天】构建安全的Java Socket通信涉及SSL/TLS加密、异常处理和重连策略。示例中,`SecureServer`使用SSLServerSocketFactory创建加密连接,而`ReliableClient`展示异常捕获与自动重连。理解安全意识,如防数据截获和中间人攻击,是首要步骤。通过良好的编程实践,确保网络应用在复杂环境中稳定且安全。
|
1天前
|
消息中间件 监控 Java
Java 框架界的‘巨星’Spring,让你的代码翩翩起舞!
【6月更文挑战第25天】Spring,Java框架的明星,以其依赖注入(DI)和面向切面编程(AOP)简化开发。DI协调类间协作,AOP提供日志、监控等附加功能。事务管理确保代码稳定性,注解如`@Transactional`自动化事务处理。Spring的集成能力使代码灵活适应多样技术场景,让编程变得优雅高效,犹如舞蹈般流畅。跟随Spring,让代码起舞!
|
1天前
|
供应链 Java 开发者
Spring 框架:Java 界的‘万能钥匙’,你的企业应用开发新宠!
【6月更文挑战第25天】# Spring框架:Java开发的基石!它提供一站式解决方案,涵盖依赖注入、AOP、事务管理等,简化复杂应用开发。通过注解如`@Service`、`@Autowired`实现代码解耦,`@Transactional`自动化事务处理,加上AOP实现全局日志记录,让维护变得简单。Spring,企业级开发的首选!
|
1天前
|
Java 程序员 调度
Java并发编程之Executor框架深度解析
【6月更文挑战第24天】在Java的并发编程领域,Executor框架是处理多线程任务的核心。本文将深入探讨Executor框架的设计哲学、核心组件以及如何高效利用这一框架来提升程序的性能和响应性。我们将通过实例演示如何正确配置和使用Executor,并讨论常见的陷阱与最佳实践。
|
2天前
|
Java 测试技术 Python
《手把手教你》系列基础篇(八十一)-java+ selenium自动化测试-框架设计基础-TestNG如何暂停执行一些case(详解教程)
【6月更文挑战第22天】本文介绍了如何在TestNG中不执行特定测试用例。当部分模块未准备好时,可以通过以下方式暂停测试:③使用`@Test(enabled=false)`注解来禁用测试用例。作者提供了一个Java Selenium自动化测试的示例,展示如何通过修改`enabled`参数控制测试方法的执行。代码中,`testSearch2()`方法被禁用,因此在测试运行时不执行。文章还包含了测试报告和执行过程的截图。
33 7
|
1天前
|
Java 开发者 Spring
从入门到精通,Spring 框架带你玩转 Java 企业应用开发!
【6月更文挑战第25天】Spring框架简化了Java企业开发,通过依赖注入降低耦合,如使用构造函数注入`UserService`中的`UserDao`。它还提供声明式事务管理,如`@Transactional`注解自动处理事务,减少手动错误。此外,Spring的AOP支持允许在不侵入业务逻辑的情况下实现横切关注点,如`LoggingAspect`所示。无论是新手还是资深开发者,Spring以其全面的功能和灵活性成为企业应用开发的强大工具。
|
1天前
|
前端开发 Java 开发者
Spring 框架:Java 企业应用开发领域的“隐形冠军”!
【6月更文挑战第25天】Spring框架在Java开发中扮演重要角色,提倡依赖注入、事务管理及面向切面编程的最佳实践。例如,通过`@Autowired`实现接口注入,保持代码松耦合;使用`@Transactional`确保数据一致性;借助`@Aspect`定义AOP切面,分离关注点;使用Java配置增强可维护性;以及在Spring MVC中利用注解驱动提升Web应用效率。遵循这些最佳实践,开发者能打造高效、可扩展的应用。
|
1天前
|
Java
java线程之分支合并框架
java线程之分支合并框架
9 1
|
1天前
|
安全 Java
java线程之List集合并发安全问题及解决方案
java线程之List集合并发安全问题及解决方案
7 1
|
2天前
|
XML Java 测试技术
《手把手教你》系列基础篇(八十二)-java+ selenium自动化测试-框架设计基础-TestNG测试报告-上篇(详解教程)
【6月更文挑战第23天】TestNG 是一个用于自动化测试的 Java 框架,它自动生成测试报告,包括 HTML 和 XML 格式。报告可在 `test-output` 文件夹中找到。要创建测试用例,可创建一个实现了 `@Test` 注解的方法。通过 `testng.xml` 配置文件来组织和执行测试。默认报告包括测试结果、失败点和原因。用户还能实现 `ITestListener` 和 `IReporter` 接口来自定义报告和记录器。
19 2