sprinboot整合shiro,MD5加密,加盐

SpringBoot实现Md5对数据库数据加密 MD5消息摘要算法,属Hash算法一类。MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要(32位的数字字母混合码)。AES算法全称Advanced Encryption Standard,又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院 (NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。 阅读详情
  1. 前段时间看到的springboot和shiro整合的视频,现特意在此进行展示出来,方便以后来进行查看,看过的朋友点个赞是最好的,自己加油!
  2. 说起整合,必须要搭建的是springboot的环境,以及进行shiro整合包的导入,项目是做的mavne项目,后期会陆续推送springboot与websocket的整合,springboot全局异常处理,springboot与quartz整合,springboot中AOP的处理,springboot与图片验证码整合,springboot与redis整合,springboot中cookie存储token以及redis中存储token的工具类,springboot文件的上传与下载。
  3. springmvc的注解使用,mysql读写分离的代码,数据库账号密码加密。赞时想到的就这么些,后面会陆续更新!!!
  4. 也需要进行博客排榜的好看,文章样式会随时改变。
  5. 话不多说,直接上sql,以及springboot与shiro整合类,以及所对应的自定义realm类。
  6. 添加model类 
    1. User表,一个用户对应多个角色,@Data是装了lombok插件的一个属性,替代get,set,toString方法等,不清楚的话,各位具体查下。
    2. /**
       * @program: shiro
       * @description: 用户
       * @author: Join
       * @create: 2018-12-10 22:29
       **/
      @Data
      public class User {
      	private int uid;
      	private String username;
      	private String password;
      	private Set<Role> roles = new HashSet<>();
      }

       

    3. Permission表
      1. @Data
        public class Permission {
        	private int pid;
        	private String name;
        	private String url;
        }

         

    4. Role表:一个角色有多个用户,一个角色有多个权限
      1. @Data
        public class Role {
        	private int rid;
        	private String rname;
        	private Set<User> userSet = new HashSet<>();
        	private Set<Permission> permissions = new HashSet<>();
        }

         

  7. 先添加pom文件
    <?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 http://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>1.5.6.RELEASE</version>
    		<relativePath/> <!-- lookup parent from repository -->
    	</parent>
    	<groupId>com.jiaolin</groupId>
    	<artifactId>shiromd5</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>war</packaging>
    	<name>shiromd5</name>
    	<description>Demo project for Spring Boot</description>
    
    	<properties>
    		<java.version>1.8</java.version>
    	</properties>
    
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    
    		<dependency>
    			<groupId>org.mybatis.spring.boot</groupId>
    			<artifactId>mybatis-spring-boot-starter</artifactId>
    			<version>1.3.1</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</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.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>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-context-support</artifactId>
    			<version>4.2.3.RELEASE</version>
    		</dependency>
    
    		<dependency>
    			<groupId>org.apache.tomcat.embed</groupId>
    			<artifactId>tomcat-embed-jasper</artifactId>
    		</dependency>
    
    		<dependency>
    			<groupId>javax.servlet</groupId>
    			<artifactId>javax.servlet-api</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>javax.servlet</groupId>
    			<artifactId>jstl</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.projectlombok</groupId>
    			<artifactId>lombok</artifactId>
    			<version>1.16.20</version>
    			<scope>provided</scope>
    		</dependency>
    	</dependencies>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    
    	<repositories>
    		<repository>
    			<id>spring-snapshots</id>
    			<name>Spring Snapshots</name>
    			<url>https://repo.spring.io/snapshot</url>
    			<snapshots>
    				<enabled>true</enabled>
    			</snapshots>
    		</repository>
    		<repository>
    			<id>spring-milestones</id>
    			<name>Spring Milestones</name>
    			<url>https://repo.spring.io/milestone</url>
    			<snapshots>
    				<enabled>false</enabled>
    			</snapshots>
    		</repository>
    	</repositories>
    
    	<pluginRepositories>
    		<pluginRepository>
    			<id>spring-snapshots</id>
    			<name>Spring Snapshots</name>
    			<url>https://repo.spring.io/snapshot</url>
    			<snapshots>
    				<enabled>true</enabled>
    			</snapshots>
    		</pluginRepository>
    		<pluginRepository>
    			<id>spring-milestones</id>
    			<name>Spring Milestones</name>
    			<url>https://repo.spring.io/milestone</url>
    			<snapshots>
    				<enabled>false</enabled>
    			</snapshots>
    		</pluginRepository>
    	</pluginRepositories>
    
    </project>
    

     

  8. /*
     Navicat Premium Data Transfer
    
     Source Server         : localhost
     Source Server Type    : MySQL
     Source Server Version : 50722
     Source Host           : localhost:3306
     Source Schema         : apache_shiro
    
     Target Server Type    : MySQL
     Target Server Version : 50722
     File Encoding         : 65001
    
     Date: 17/12/2018 12:19:21
    */
    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for permission
    -- ----------------------------
    DROP TABLE IF EXISTS `permission`;
    CREATE TABLE `permission`  (
      `pid` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
      `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
      PRIMARY KEY (`pid`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of permission
    -- ----------------------------
    INSERT INTO `permission` VALUES (1, 'add', '');
    INSERT INTO `permission` VALUES (2, 'delete', '');
    INSERT INTO `permission` VALUES (3, 'edit', '');
    INSERT INTO `permission` VALUES (4, 'query', '');
    
    -- ----------------------------
    -- Table structure for permission_role
    -- ----------------------------
    DROP TABLE IF EXISTS `permission_role`;
    CREATE TABLE `permission_role`  (
      `rid` int(11) NOT NULL,
      `pid` int(11) NOT NULL,
      INDEX `idx_rid`(`rid`) USING BTREE,
      INDEX `idx_pid`(`pid`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of permission_role
    -- ----------------------------
    INSERT INTO `permission_role` VALUES (1, 1);
    INSERT INTO `permission_role` VALUES (1, 2);
    INSERT INTO `permission_role` VALUES (1, 3);
    INSERT INTO `permission_role` VALUES (1, 4);
    INSERT INTO `permission_role` VALUES (2, 1);
    INSERT INTO `permission_role` VALUES (2, 4);
    
    -- ----------------------------
    -- Table structure for role
    -- ----------------------------
    DROP TABLE IF EXISTS `role`;
    CREATE TABLE `role`  (
      `rid` int(11) NOT NULL AUTO_INCREMENT,
      `rname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
      PRIMARY KEY (`rid`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of role
    -- ----------------------------
    INSERT INTO `role` VALUES (1, 'admin');
    INSERT INTO `role` VALUES (2, 'customer');
    
    -- ----------------------------
    -- Table structure for user
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user`  (
      `uid` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
      `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
      PRIMARY KEY (`uid`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES (1, 'admin', 'c41d7c66e1b8404545aa3a0ece2006ac');
    INSERT INTO `user` VALUES (2, 'demo', '376204ce2cde0c12bc1ac7ff3651bd93');
    
    -- ----------------------------
    -- Table structure for user_role
    -- ----------------------------
    DROP TABLE IF EXISTS `user_role`;
    CREATE TABLE `user_role`  (
      `uid` int(11) NOT NULL,
      `rid` int(11) NOT NULL,
      INDEX `idx_uid`(`uid`) USING BTREE,
      INDEX `idx_rid`(`rid`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of user_role
    -- ----------------------------
    INSERT INTO `user_role` VALUES (1, 1);
    INSERT INTO `user_role` VALUES (2, 2);
    
    SET FOREIGN_KEY_CHECKS = 1;
    

     

  9. 自定义realm类,需要继承 AuthorizingRealm

    package com.jiaolin.shiro.config;
    
    import com.jiaolin.shiro.model.Permission;
    import com.jiaolin.shiro.model.Role;
    import com.jiaolin.shiro.model.User;
    import com.jiaolin.shiro.service.UserService;
    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.util.ByteSource;
    import org.apache.shiro.util.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Set;
    
    /**
     * @program: shiro
     * @description: 自定义认证器
     * @author: Join
     * @create: 2018-12-10 23:24
     **/
    public class AuthRealm extends AuthorizingRealm {
    
        @Autowired
        private UserService userService;
    
        /**
         * @Description: 授权 1 拿到对应的用户,根据用户拿到角色(admin,customer)
         * 和权限的名字(增删改查)
         * @Param: [principalCollection]
         * @return: org.apache.shiro.authz.AuthorizationInfo
         * @Author: Join
         * @Date: 23:26
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
            User user = (User) principal.fromRealm(this.getClass().getName()).iterator().next();
            Set<Role> roles = user.getRoles();
            List<String> roleList = new ArrayList<>();
            List<String> permissionList = new ArrayList<>();
            if (!CollectionUtils.isEmpty(roles)) {
                for (Role role : roles) {
                    roleList.add(role.getRname());
                    Set<Permission> permissions = role.getPermissions();
                    if (!CollectionUtils.isEmpty(permissions)) {
                        for (Permission permission : permissions) {
                            permissionList.add(permission.getName());
                        }
                    }
                }
            }
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.addRoles(roleList);
            info.addStringPermissions(permissionList);
            return info;
        }
    
        /**
         * @Description: 认证
         * @Param: [authenticationToken]
         * @return: org.apache.shiro.authc.AuthenticationInfo
         * @Author: Join
         * @Date: 23:26
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            //token携带了用户信息
            UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
            //获取前端输入的用户名
            String userName  = usernamePasswordToken.getUsername();
            //根据用户名查询数据库中对应的记录
            User user = userService.findUserByUsername(userName);
            //当前realm对象的name
            String realmName = getName();
            //盐值
            ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername());
            //封装用户信息,构建AuthenticationInfo对象并返回
            AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user, user.getPassword(),
                    credentialsSalt, realmName);
            return authcInfo;
        }
    }

     

  10. 然后在进行shiro配置

    @Configuration
    public class ShiroConfig {
    
    
        /**
         * 密码校验规则HashedCredentialsMatcher
         * 这个类是为了对密码进行编码的 ,
         * 防止密码在数据库里明码保存 , 当然在登陆认证的时候 ,
         * 这个类也负责对form里输入的密码进行编码
         * 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher
         */
        /**
        * @Description: 下面为添加的
        * @Param: []
        * @return: HashedCredentialsMatcher
        * @Author: Join
        * @Date: 2018/12/13
        */
        @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 securityManager
         * @return
         */
        @Bean("shiroFilter")
        public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager) {
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            bean.setSecurityManager(securityManager);
            bean.setLoginUrl("/login");
            bean.setSuccessUrl("/index");
            bean.setUnauthorizedUrl("/unauthorized");
            LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
            filterChainDefinitionMap.put("/index", "authc");
            filterChainDefinitionMap.put("/login", "anon");
            filterChainDefinitionMap.put("/loginUser", "anon");
            //角色为admin的用户才能访问admin网页
            filterChainDefinitionMap.put("/admin", "roles[admin]");
            //权限为edit的角色才能访问edit页面
            filterChainDefinitionMap.put("/edit", "perms[edit]");
            filterChainDefinitionMap.put("/druid/**", "anon");
            //另外的页面需要用户进行登录才能访问
            filterChainDefinitionMap.put("/**", "user");
            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();
        }
    
        public static void main(String[] args) {
            String hashAlgorithName = "MD5";
            String password = "123";
            int hashIterations = 1024;//加密次数
            ByteSource credentialsSalt = ByteSource.Util.bytes("admin");
            Object obj = new SimpleHash(hashAlgorithName, password, credentialsSalt, hashIterations);
            System.out.println(obj);
        }
    }

     

  11. spring和shiro的配置算完成了,然后在来看看登录与登出的操作怎么写,页面的话,后面在进行写进来。

    @Controller
    public class UserController {
    
        /**
         * @Description: 用户登录 登录成功返回index 失败跳转到login
         * @Param: [username, password]
         * @return: java.lang.String
         * @Author: Join
         * @Date: 23:13
         */
        @RequestMapping("/loginUser")
        public String login(@RequestParam("username") String username,
                            @RequestParam("password") String password, HttpSession session) {
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            Subject subject = SecurityUtils.getSubject();
            try {
                subject.login(token);
                //获取主体
                User user = (User) subject.getPrincipal();
                //并设置在session中
                session.setAttribute("user", user);
                return "index";
            } catch (Exception e) {
                e.printStackTrace();
                return "login";
            }
        }
    
        /**
         * @Description: 跳转登录页面
         * @Param: []
         * @return: java.lang.String
         * @Author: Join
         * @Date: 23:20
         */
        @RequestMapping("/login")
        public String login() {
            return "login";
        }
    
        /**
         * @Description: admin登录成功
         * @Param: []
         * @return: java.lang.String
         * @Author: Join
         * @Date: 23:20
         */
        @RequestMapping("/admin")
        @ResponseBody
        public String admin() {
            return "admin success";
        }
    
    
        /**
         * @Description: 跳转到index页面
         * @Param: []
         * @return: java.lang.String
         * @Author: Join
         * @Date: 23:20
         */
        @RequestMapping("/index")
        public String index() {
            return "index";
        }
    
        /**
         * @Description: 登出
         * @Param: []
         * @return: java.lang.String
         * @Author: Join
         * @Date: 23:14
         */
        @RequestMapping("/logout")
        public String logout() {
            Subject subject = SecurityUtils.getSubject();
            if (subject != null) {
                subject.logout();
            }
            return "login";
        }
    
        /**
         * @Description: 授权不成功跳转页面
         * @Param: []
         * @return: java.lang.String
         * @Author: Join
         * @Date: 23:19
         */
        @RequestMapping("/unauthorized")
        public String unauthorized() {
            return "unauthorized";
        }
    
        /**
         * @Description: 编辑成功
         * @Param: []
         * @return: java.lang.String
         * @Author: Join
         * @Date: 23:18
         */
        @RequestMapping("/edit")
        @ResponseBody
        public String edit() {
            return "edit success";
        }
    }

     

  12. 获取认证的时候需要调用service,以及dao层,先添出来,接口就不添了。

    1. @Service
      public class UserServiceImpl implements UserService {
      	@Autowired
      	private UserMapper userMapper;
      
      	@Override
      	public User findUserByUsername(String name) {
      		return userMapper.findUserByUsername(name);
      	}
      }

       

    2. public interface UserMapper {
      	User findUserByUsername(String username);
      }

       

    3. <?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.jiaolin.shiro.mapper.UserMapper">
          <resultMap id="baseUserMap" type="com.jiaolin.shiro.model.User">
              <id property="uid" column="uid"/>
              <result property="username" column="username"/>
              <result property="password" column="password"/>
              <collection property="roles" ofType="com.jiaolin.shiro.model.Role">
                  <id property="rid" column="rid"/>
                  <result property="rname" column="rname"/>
                  <collection property="permissions" ofType="com.jiaolin.shiro.model.Permission">
                      <id property="pid" column="pid"/>
                      <result property="name" column="name"/>
                      <result property="url" column="url"/>
                  </collection>
              </collection>
          </resultMap>
      
      
          <select id="findUserByUsername" parameterType="string" resultMap="baseUserMap">
              SELECT u.*,r.*,p.*
              FROM  user u
              INNER JOIN user_role ur ON u.uid=ur.uid
              INNER JOIN role r ON r.rid=ur.rid
              INNER JOIN permission_role pr ON pr.rid=r.rid
              INNER JOIN permission p ON p.pid=pr.pid
              WHERE u.username=#{username,jdbcType=VARCHAR}
          </select>
      </mapper>

       

  13. 最后的话,在项目的properties进行全局配置,以及页面的布置,

    ## database ##
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/apache_shiro?characterEncoding=UTF-8
    spring.datasource.username=root
    spring.datasource.password=root
    server.port=8081
    ## mybatis ##
    mybatis.mapper-locations=mapper/*.xml
    mybatis.type-aliases-package=com.jiaolin.shiro.model
    
    ## jsp ##
    spring.mvc.view.prefix=/page/
    spring.mvc.view.suffix=.jsp

     

  14. 
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>index</title>
    </head>
    <body>
    <h3>欢迎你登录 ${user.username}</h3>
    </body>
    </html>
    
    
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Login</title>
    </head>
    <body>
    <h2>欢迎登陆</h2>
    <form action="/loginUser" method="post">
        <input type="text" name="username"> <br>
        <input type="password" name="password"> <br>
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>UnAuthorized</title>
    </head>
    <body>
    <h3>UnAuthorized</h3>
    </body>
    </html>
    
    

    以上的这些都是JSP页面,为了简便,全部打上了html标签了。springboot项目中默认页面是放到webapp中,和resources同级,懂一点常识的人都知道,这上面的博客为一篇最简单的博客,没做多大的校验,也没有所谓的弄redis集群版,后续会连续发布其余的整合,也是相对较简单的入门篇,源码的话,就不看了,虽然看懂一点点,毕竟我也是一菜鸟,经过本人测试是OK的,爱学习的人欢迎留言咨询,不喜的人也勿喷,如要转载,请经过本人同意。后面做的记录,跟博客没有一点点关联,建议不要看,只是我每天上下班挤地铁时候看的2个小时的书籍做的一点感想。做下记录,以便给我自己脑海中留点记录。

  15. 最后,在此对前面2天看过的书籍,学习的精进,其中回忆的两点进行记录,

    1. 1-3-12学习法,意思就是说坚持1个月,3个月,12个月,

    2. 1-3-10学习法,意思就是坚持1年,3年,10年,这也就是所说的10年学习法,10年之后,你必定是一个不一样的自己,加油。

    3. 适当学习法:

    4. 输入输出法:以输入和输出的比列来算,3:7的概率来讲,这是所谓的黄金比例,如果没有输出,就减少输入。

  16. 对于精英这样用脑不会累写下自我感言

    1. 每天设定一个小目标,想办法完成。

    2. 完成这个小目标后,在继续指定更大的目标。

    3. 完成目标后,给自己一些奖赏。

    4. 目标不要不切实际,那样会坚持不下去的。加油。

【SpringBoot】MD5加盐算法的详解 本期讲解:如何使用MD5实现加盐算法。 阅读详情

相关推荐

SpringBoot 系列教程(八十五):Spring Boot使用MD5加盐验签Api接口之前后端分离架构设计

一、前言 在当下的Web开发,或者涉及到H5、APP、小程序等移动端开发时,务必需要后端提供Api接口供前端调用,无论H5程序、App还是小程序,都是如此,那么接口安全问题就被大家重视起来了,现在也越来越多人关注接口安全问题,尤其是一些架构师,传统的接口在传输的过程中,容易被抓包然后更改里面的参数值达到某些目的。传统的做法是用安全框架或者在代码里面做验证,但是有些系统是不需要登录的,随时可以调AP...

Thinkingcao的专栏 9625

Java基础类(七):CollectionUtils工具类

发发发

mingyuli的博客 1920

光学设计必知:Ansys Zemax中6种系统孔径类型的适用场景全解析

本文深入解析Ansys Zemax中6种系统孔径类型的适用场景,包括入瞳直径、像方空间F/#、物方空间NA等,帮助光学设计师精准控制光线选择和成像质量。通过实际案例和代码示例,详细讲解各孔径类型的计算原理、参数设置及在显微系统、激光扩束等场景中的优化策略,提升复杂光学系统设计效率。

weixin_29266007的博客 551

CollectionUtils属于哪个包

使用的场景: 今天在自己的demo项目中写代码时需要对list进行判空的出来, 我们都知道 先对list 是否为null 是否为为空(isEapty) 但是我不习惯这样的写,在工作中使用 工具类习惯了 CollectionUtils.isEpty( list) 防止 NPM的异常出现 我遇到了问题平时是直接拿来用的,pom文件中如何导入.没事我看我们项目中的pom文件直接cop...

徐小冠 1万+

利用gprMax与Matlab实现SFCW雷达信号的高效仿真与优化

本文详细介绍了如何结合gprMax与Matlab实现SFCW雷达信号的高效仿真与优化。通过利用gprMax获取地下场景的冲激响应,并在Matlab中运用卷积与信号处理技术,可大幅提升SFCW雷达系统仿真的效率与灵活性,为探地雷达研究与设计提供强大工具。

book8的博客 705

实测OV5640 DVP/MIPI接口720p@60fps配置,为什么我的Zynq-7020开发板只有30帧?

本文深入解析了OV5640摄像头在Zynq-7020开发板上帧率减半的问题,从寄存器配置到硬件链路进行全面排查。重点分析了DVP/MIPI接口的720p@60fps配置,提供了关键寄存器设置、时序参数调整及硬件带宽验证方法,帮助开发者快速定位并解决帧率下降问题。

weixin_42634811的博客 344

springboot连接数据库实现md5+salt加密demo(用户登录注册详细源码)

springboot连接数据库实现md5+salt加密,用户注册,登录测试demo

mest的博客 4029

[官方培训]19-物理模拟 Epic 肖月 笔记

物理引擎全局解算精度的设置,帧率越高,子步越多得到的模拟结果就越精确。引擎默认情况下是以变化的帧率运行的,但是对于Chaos物理引擎来说。一般子步越小,帧率越固定,效果就会更好更稳定一些。图示的分步选项就是依据下方的最长子步时长和最大步数对动态变化的帧率,进一步的做拆分来保证物理效果。对于影视项目建议都开启分步选项。红色框内有三个迭代次数的设置,这是Chaos基于位置的约束求解算法专用的一个设置,可以简单理解为迭代次数越高,当前帧一个子步内得到的结果就越精确。

Tcohneyn的博客 1545

Spring Boot 整合Shiro(二)加密登录与密码加盐处理

该项目是根据上篇《Spring Boot 整合Shiro(一)登录认证和授权(附源码)》进行配置,若有不明白的请先查看上篇文章。 1.加密工具 用户注册时的密码用这个加密保存数据库 /** * 账户密码加密 * @param username * @param pwd * @return */ public static S...

云下的你 1692

【100%通过率】华为od统一考试B卷【查找接口成功率最优时间段】Python 实现

服务之间交换的接口成功率作为服务调用关键质量特性,某个时间段内的接口失败率使用一个数组表示,数组中每个元素都是单位时间内失败率数值,数组中的数值为0~100的整数, 给定一个数值(minAverageLost)表示某个时间段内平均失败率容忍值,即平均失败率小于等于minAverageLost,找出数组中最长时间段,如果未找到则直接返回NULL。

MISAYAONE的博客 5868

【05】昊一源科技——昊一源科技 嵌入式笔试, 校招,题目记录及解析

本文记录了昊一源科技嵌入式校招笔试题目及解析,涵盖计算机基础、汇编语言、网络协议、C语言编程等内容。主要包括:1)补码真值计算;2)MCS51汇编指令执行后寄存器状态;3)网络广播地址计算;4)TCP协议特点;5)C语言三目运算符应用;6)宏定义优先级问题;7)字符指针与数组的区别;8)C++静态成员变量应用;9)三位完全平方数查找程序。题目难度适中,涉及嵌入式开发常见知识点,对求职者基础能力考察全面。

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 1307

springboot整合shiro

springboot + shiro + easyui 搭建后台项目 目录 springboot + shiro + easyui 搭建后台项目 (一):shiro配置自定义Realm realm的概念 自定义realm (二):配置MD5加密 认证匹配器 MD5工具类 (三):shiroFilter的配置 (四):自定义表单认证 (五):登出处理 (六):shiro表...

qq_41630334的博客 484

PCB_Project.PrjPcb 4 Not in version control

Altium Designer中PCB项目出现"NOT in version control"错误的解决方法:1. 禁用不需要的版本控制集成(DXP→Preferences→Version Control);2. 清理项目缓存(Projects面板右键→Clean Project);3. 检查文件读写权限;4. 如无效可新建项目重新添加文件。如需使用SVN版本控制,需正确配置SVN客户端路径,创建或连接SVN仓库,并将项目文件提交至版本控制系统。注意新建SVN仓库必须使用空目录,建议使用

whm128的博客 1590

Sprinboot mybatis整合shiro 登录,权限管理

首先感谢慕课网的老师,让我受益匪浅 https://www.imooc.com/video/16961   整体源码  github地址:https://github.com/binlian/binglian-shiroLoginResit 实现了登录才可以访问其他网站, 实现了管理员的权限以及用户的权限, 我先总结一下所学的 我这里借用一下老师的图片 上面的C/C++、PHP这...

xiaoxin0630的博客 429

用扩展点为 Fiori Elements 添加自定义动作:从原理到落地的完整实践

本文介绍了如何在基于OData V4的Fiori Elements应用中通过Extension Points添加自定义Action按钮。主要内容包括: 扩展点动作与标准注解动作的区别:扩展点用于非标准前端流程、组合操作等场景,需通过extensionAPI与框架交互。 扩展点动作的插入位置:可放置在List Report表格工具栏、Object Page页眉/页脚/Section工具栏等位置,并说明了相应的manifest.json配置节点。 配置模型与处理函数契约:详细说明了press、visible/e

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 248

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

SpringBoot 与Shiro 整合系列(三)多Realm验证和认证策略

系列(三)讲述 SpringBoot整合Shiro 实现多Realm验证以及认证策略 目录一、使用场景二、多Realm验证配置流程:1.添加第二个Realm SecondRealm.java三、认证策略1.概念2.认证策略的使用2.1 默认使用2.1 切换认证策略 一、使用场景 我们可能会把安全数据放到不同的表中,比方说 不同类型的用户登录,这个时候我们进行用户认证时,就需要进行不同的逻辑处理,就需要多个Realm。如果有多个Realm的话,还需要涉及到认证策略的问题。 二、多Realm验证 多重认证,主要

12程序猿的博客 1520

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Springboot--内置的MD5加盐加密

文章目录 【笔记于学习尚硅谷课程所作】 MD5 Message Digest algorithm 5,信息摘要算法 压缩性:任意长度的数据,算出的MD5值长度都是固定的。 容易计算:从原数据计算出MD5值很容易。 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。 强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。 不可逆 (加盐) 通过生成随机数与MD5生成字符串进行组合 数据库同时存储MD5值与salt值。验证正确性时使用salt进行M

一个巨大的博客 4877

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

springboot md5加密 加盐

修改密码

面朝大海,春暖花开 1009

【Spring篇】 项目加盐加密处理

Spring Security 实现项目的加盐加密

m0_56361048的博客 2087

加盐算法(Spring Boot)

2.MD5加密的密码是有规律可循的,因为所有固定的字符都会有固定的 MD5,因此如果有一个库(彩虹库{字符 | 字符的MD5 })带有所有的字符和字符的MD5,就可以破解所有的MD5加密了.salt 的长度是 32位. UUID是由32位字符加4个分隔符 ("-") 组成的.由于repalce去掉了分隔符,因此就剩32位了.最终返回的密码是 32+1('$'分隔符)+32=65位.也就是说最终返回的密码一定是65位的.MD5加密的得到的密码是32位的,因此finalPassword是32位的.

f7ashion的博客 993

Shiro的MD5加盐

让shiro来做密码比对 shiro的配置文件中将HashedCredentialsMatcher 注入 @Bean public HashedCredentialsMatcher credentialsMatcher() { HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); //设置加密的方式 credentialsMatcher.se

qq_45308061的博客 284

(转)Apache Commons工具集简介

Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动。我选了一些比较常用的项目做简单介绍。文中用了很多网上现成的东西,我只是做了一个汇总整理。 一、Commons BeanUtils http://jakarta.apache.org/commons/beanutils/index.html 说明:针对Bean的一个工具集。由于Bean往往是有一堆get...

jackyrongvip的专栏 626

SpringBoot整合MD5加密完成注册和登录

【代码】SpringBoot整合MD5加密完成注册和登录。

2301_81405087的博客 3228

Shiro中的MD5和盐

Shiro的MD5和Salt 1. 原理 用户注册时 生成一段随机字符串,一般使用UUID,生成的字符串即所谓的salt 将用户输入的密码+salt,整体进行加密, 将加密后的数据存储到数据库, salt也应该存储到数据库中。 用户登录时 将用户输入的密码+salt,整体进行加密 与数据库中存储的数据进行比对 相同则为密码正确,不同则为密码错误 2. md5哈希散列 /** * @Author: Hjx * @Date: 2021/8/9 17:24 */ public class TestS

萝卜_7 517

【Shiro权限管理】10.Shiro为密码加盐

上一篇我们提到了使用Shiro为密码进行MD5加密,这次来说一下密码加盐的问题。 当两个用户的密码相同时,单纯使用不加盐的MD5加密方式,会发现数据库中存在相同结构的密码, 这样也是不安全的。我们希望即便是两个人的原始密码一样,加密后的结果也不一样。 如何做到呢?其实就好像炒菜一样,两道一样的鱼香肉丝,加的盐不一样,炒出来的味道就不一样。 MD5加密也是一样,需要进行盐值加密。 在之

程序猿之洞 3万+

Shiro学习(六)——MD5加密与盐值

前言 上一篇文章讲了shiro如何配置加密服务。这篇文章我们用md5加密算法作为例子。md5算法是常见的加密算法,另外为了提高安全性,通常还会加上盐值。这些如何进行配置呢,在本文进行展示 ...

sadoshi的专栏 1938
下一篇: 关于debug记录
JJoinLin
博客等级 码龄9年 1粉丝 2原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值