springboot整合shiro(含MD5加密)(上)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 关于shiro介绍以及shiro整合spring,我在另一篇文章中已详细介绍,此处不作说明,请参考spring整合shiro。

项目开始:


一、数据库设计:


注:数据库三张表和spring整合shiro中的一模一样,在那边已经详细说明,这里直接大家看下三张表的ER图。


image.png


二、添加依赖,配置mybatis


1、用idea新建Spring Initializr项目,项目结构如下:


image.png


2、添加依赖:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.20</version>
        </dependency>
        <!--常用的工具包-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
        <!--spring的上下文工具包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <!--对jsp的处理-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </dependency>
    </dependencies>


3、application.properties

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql:///#
spring.datasource.username=#
spring.datasource.password=#
## mybatis ##
mybatis.mapper-locations=mappers/*.xml
mybatis.type-aliases-package=com.zhu.shiro.entity
## 视图解析器 ##
spring.mvc.view.prefix=/pages/
spring.mvc.view.suffix=.jsp


三、项目设计


注:spring整合shiro中是只有User实体类,在UserDao中定义了三个方法,通过表的关键关系查询Role和Permission;这里将采用另一种方式,三个实体类,设置实体类的关联关系。


1、entity层


User.java

public class User {
    private  Integer uid;
    private  String username;
    private  String password;
    private  Set<Role> roles = new HashSet<>();
}


Role.java

public class Role {
    private  Integer rid;
    private  String name;
    private  Set<Permission> permissions = new HashSet<>();
}


Permission.java

public class Permission {
    private  Integer pid;
    private  String  name;
}


2、dao层


UserDao.java

public interface UserDao {
    User findByUsername(String username);
}


UserDao.xml

<?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">
<mapper namespace="com.zhu.shiro.dao.UserDao">
    <resultMap id="userMap" type="com.zhu.shiro.entity.User">
        <id property="uid" column="uid"/>
        <result property="username" column="user_name"/>
        <result property="password" column="pass_word"/>
        <collection property="roles" ofType="com.zhu.shiro.entity.Role">
            <id property="rid" column="rid"/>
            <result property="name" column="role_name"/>
            <collection property="permissions" ofType="com.zhu.shiro.entity.Permission">
                <id property="pid" column="pid"/>
                <result property="name" column="permission_name"/>
            </collection>
        </collection>
    </resultMap>
    <select id="findByUsername" parameterType="string" resultMap="userMap">
           SELECT *
           FROM tb_user u,tb_role r,tb_permission p
           WHERE u.rid=r.rid
           AND p.rid=r.rid
           AND u.user_name=#{username}
    </select>
</mapper>


3、service层

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Override
    public User findByUsername(String username) {
        return userDao.findByUsername(username);
    }
}


4、junit测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceImplTest {
    @Autowired
    private UserService userService;
    @Test
    public void findByUsername() {
        User u = userService.findByUsername("tom");
        Set<Role> roleSet = u.getRoles();
        for (Role role : roleSet){
            Set<Permission> permissionSet = role.getPermissions();
            for (Permission permission : permissionSet){
                System.out.println(permission.getName());
            }
            System.out.println(role.getName());
        }
    }
}



image.png


数据库中tom是admin角色,有增删改查权限,符合预期,测试通过。


5、controller层


TestController.java

@Controller
public class TestController {
    //用户登录
    @RequestMapping("/loginUser")
    public String loginUser(@RequestParam("username") String username,
                            @RequestParam("password") String password,
                            HttpSession session) {
        //把前端输入的username和password封装为token
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            session.setAttribute("user", subject.getPrincipal());
            return "index";
        } catch (Exception e) {
            return "login";
        }
    }
    //退出登录
    @RequestMapping("/logout")
    public String logout() {
        Subject subject = SecurityUtils.getSubject();
        if (subject != null) {
            subject.logout();
        }
        return "login";
    }
    //访问login时跳到login.jsp
    @RequestMapping("/login")
    public String login() {
        return "login";
    }
    //admin角色才能访问
    @RequestMapping("/admin")
    @ResponseBody
    public String admin() {
        return "admin success";
    }
    //有delete权限才能访问
    @RequestMapping("/edit")
    @ResponseBody
    public String edit() {
        return "edit success";
    }
    @RequestMapping("/test")
    @ResponseBody
    @RequiresRoles("guest")
    public String test(){
        return "test success";
    }
}


说明:这里用户登录方法用到了shiro,但是这里还没配置shiro,所以暂时不能使用,先搭起整个骨架,然后再加入shiro。


6、jsp页面


login.jsp


(登录页面)

%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Login</title>
</head>
<body>
   <h1>欢迎登录!</h1>
   <form action="/loginUser" method="post">
       <input type="text" name="username"><br>
       <input type="password" name="password"><br>
       <input type="submit" value="提交">
   </form>
</body>
</html>


index.jsp


(登录成功跳转的页面)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
   <h1>欢迎登录,${user.username}</h1>
</body>
</html>


unauthorized.jsp


(无权访问跳转的页面)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>unauthorized</title>
</head>
<body>
unauthorized!
</body>
</html>


现在说一下要求:


admin路由要求只有具有admin角色的用户才能访问,edit路由需要有delete权限的用户才能访问,test路由要guest角色才能访问,login、loginUser都不做拦截,本文讲解两种拦截方式,对test的拦截是在controller对应的方法上加注解,其他是拦截是写在shiro的配置类中。


预期分析:


tom是有admin角色和所有权限,所以用tom登录后,可以访问edit和admin,但是不能访问guest;而cat是guest角色,只有create和query权限,所以不能访问admin和edit,但是可以访问guest。


四、配置shiro


由于springboot还没有集成shiro,所以不能直接在application.properties中配置,需要通过类的方式配置。


核心配置类:


ShiroConfiguration.java

@Configuration
public class ShiroConfiguration {
    /**
     * 密码校验规则HashedCredentialsMatcher
     * 这个类是为了对密码进行编码的 ,
     * 防止密码在数据库里明码保存 , 当然在登陆认证的时候 ,
     * 这个类也负责对form里输入的密码进行编码
     * 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher
     */
    @Bean("hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //指定加密方式为MD5
        credentialsMatcher.setHashAlgorithmName("MD5");
        //加密次数
        credentialsMatcher.setHashIterations(1024);
        credentialsMatcher.setStoredCredentialsHexEncoded(true);
        return credentialsMatcher;
    }
    @Bean("authRealm")
    @DependsOn("lifecycleBeanPostProcessor")//可选
    public AuthRealm authRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher) {
        AuthRealm authRealm = new AuthRealm();
        authRealm.setAuthorizationCachingEnabled(false);
        authRealm.setCredentialsMatcher(matcher);
        return authRealm;
    }
    /**
     * 定义安全管理器securityManager,注入自定义的realm
     * @param authRealm
     * @return
     */
    @Bean("securityManager")
    public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(authRealm);
        return manager;
    }
    /**
     * 定义shiroFilter过滤器并注入securityManager
     * @param manager
     * @return
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置securityManager
        bean.setSecurityManager(manager);
        //设置登录页面
        //可以写路由也可以写jsp页面的访问路径
        bean.setLoginUrl("/login");
        //设置登录成功跳转的页面
        bean.setSuccessUrl("/pages/index.jsp");
        //设置未授权跳转的页面
        bean.setUnauthorizedUrl("/pages/unauthorized.jsp");
        //定义过滤器
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/index", "authc");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/loginUser", "anon");
        filterChainDefinitionMap.put("/admin", "roles[admin]");
        filterChainDefinitionMap.put("/edit", "perms[delete]");
        filterChainDefinitionMap.put("/druid/**", "anon");
        //需要登录访问的资源 , 一般将/**放在最下边
        filterChainDefinitionMap.put("/**", "authc");
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return bean;
    }
    /**
     * Spring的一个bean , 由Advisor决定对哪些类的方法进行AOP代理 .
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }
    /**
     * 配置shiro跟spring的关联
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
    /**
     * lifecycleBeanPostProcessor是负责生命周期的 , 初始化和销毁的类
     * (可选)
     */
    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
}


注:这个类每个bean的作用都已在代码中注释说明,这个类就相当于spring整合shiro的spring-shiro.xml中对shiro的配置。


相关文章
|
3月前
|
安全 Java 数据库
第16课:Spring Boot中集成 Shiro
第16课:Spring Boot中集成 Shiro
563 0
|
7月前
|
安全 Java Apache
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
331 0
|
2月前
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
711 10
|
7月前
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
257 0
|
3月前
|
人工智能 安全 Java
Spring Boot yml 配置敏感信息加密
本文介绍了如何在 Spring Boot 项目中使用 Jasypt 实现配置文件加密,包含添加依赖、配置密钥、生成加密值、在配置中使用加密值及验证步骤,并提供了注意事项,确保敏感信息的安全管理。
802 1
|
4月前
|
存储 安全 算法
用 MD5 加密 WordPress 验证码的完整教程
本文详细介绍了如何使用MD5加密技术增强WordPress验证码的安全性。通过将验证码答案以MD5形式加密并存储在Session中,避免了明文传输可能带来的安全风险。文章从形势分析、MD5算法介绍到实战操作步骤,逐步引导读者实现加密验证流程。同时提供了调试方法,确保修改生效。此教程旨在为网站添加一层安全保障,提升对抗网络攻击的能力。
242 1
|
4月前
|
缓存 安全 Java
Shiro简介及SpringBoot集成Shiro(狂神说视频简易版)
Shiro简介及SpringBoot集成Shiro(狂神说视频简易版)
308 6
|
5月前
|
存储 算法 安全
MD5加密
MD5(Message-Digest Algorithm 5)是一种单向加密算法,将任意长度的数据转换为128位固定长度的散列值,主要用于数据完整性校验和密码存储。其特点包括不可逆运算、高度离散性和相同输入生成一致结果。然而,MD5存在碰撞风险,直接加密密码不安全,需配合“加盐”处理增强安全性。文中提供了未加盐的MD5工具类`MD5Utils`,核心方法`msgToMD5`实现基本加密功能。尽管MD5理论上不可逆,但通过彩虹表等手段可能存在伪破解风险,建议结合多种加密算法提升安全性。
286 2
|
7月前
|
编解码 安全 Java
如何在Spring Boot中实现数据加密
本文介绍了如何在Spring Boot中实现数据加密。首先阐述了数据加密的重要性与应用场景,接着讲解了对称加密和非对称加密的原理及区别。通过添加依赖、配置加密算法、编写加密工具类等步骤,展示了具体实现方法,并在业务代码中应用加密技术保护敏感数据。希望对开发者有所帮助。
536 7
|
18天前
|
前端开发 安全 Java
基于springboot+vue开发的会议预约管理系统
一个完整的会议预约管理系统,包含前端用户界面、管理后台和后端API服务。 ### 后端 - **框架**: Spring Boot 2.7.18 - **数据库**: MySQL 5.6+ - **ORM**: MyBatis Plus 3.5.3.1 - **安全**: Spring Security + JWT - **Java版本**: Java 11 ### 前端 - **框架**: Vue 3.3.4 - **UI组件**: Element Plus 2.3.8 - **构建工具**: Vite 4.4.5 - **状态管理**: Pinia 2.1.6 - **HTTP客户端
120 4
基于springboot+vue开发的会议预约管理系统