Shiro certification md5 salt encryption and shiro certification test-Shiro and SSM integration

Please indicate the source for reprinting: https://blog.csdn.net/men_ma/article/details/106847165 .
This article is from the blog of Xiao Yuan Yuan, who is not afraid of reporting errors but afraid of not reporting errors.

aims

1. Shiro authentication
2. Salt encryption

table of Contents

Insert picture description here
Insert picture description here

1.shiro certification

Step 1: Import pom.xml dependencies

 <shiro.version>1.2.5</shiro.version>


 <!-- shiro核心包 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <!-- 添加shiro web支持 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>

Step 2: Configure web.xml

<!-- shiro过滤器定义 -->
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
      <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
      <param-name>targetFilterLifecycle</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

Step 3: Reverse engineering the five tables to generate corresponding model and mapper

Insert picture description here

New in Mapper:

 <select id="queryByName" resultType="com.xiaoqing.ssm.model.ShiroUser" parameterType="java.lang.String">
    select
    <include refid="Base_Column_List" />
    from t_shiro_user
    where username=#{uname}
  </select>

Service layer ShiroUserService (interface class):

package com.xiaoqing.ssm.service;

import com.xiaoqing.ssm.model.ShiroUser;
import org.apache.ibatis.annotations.Param;

/**
 * @author 晴sister
 * @site https://blog.csdn.net/men_ma
 * @company
 * @create 2020-10-2819:11
 */
public interface ShiroUserService {
    
    

    ShiroUser queryByName(String uname);

}

Service layer ShiroUserServiceIpml.java (interface implementation class):

package com.xiaoqing.ssm.service.impl;

import com.xiaoqing.ssm.mapper.ShiroRoleMapper;
import com.xiaoqing.ssm.mapper.ShiroUserMapper;
import com.xiaoqing.ssm.model.ShiroUser;
import com.xiaoqing.ssm.service.ShiroUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author 晴sister
 * @site https://blog.csdn.net/men_ma
 * @company
 * @create 2020-10-2819:55
 */
@Service("shiroUserService")
public class ShiroUserServiceImpl implements ShiroUserService {
    
    
    @Autowired
    private ShiroUserMapper shiroUserMapper;
    @Override
    public ShiroUser queryByName(String uname) {
    
    
        return shiroUserMapper.queryByName(uname);
    }
}

Step 4: Write MyReaml.java file (equivalent to ini file) to call the database

MyReaml.java:

在这里插入代码片

Step 5: Integration of shiro and spring

applicationContext-shiro.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置自定义的Realm-->
    <bean id="shiroRealm" class="com.xiaoqing.ssm.shiro.MyRealm">
        <property name="shiroUserService" ref="shiroUserService" />
        <!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
        <!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
        <!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
        <!--以下三个配置告诉shiro将如何对用户传来的明文密码进行加密-->
        <property name="credentialsMatcher">
            <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <!--指定hash算法为MD5-->
                <property name="hashAlgorithmName" value="md5"/>
                <!--指定散列次数为1024次-->
                <property name="hashIterations" value="1024"/>
                <!--true指定Hash散列值使用Hex加密存. false表明hash散列值用用Base64-encoded存储-->
                <property name="storedCredentialsHexEncoded" value="true"/>
            </bean>
        </property>
    </bean>

    <!--注册安全管理器-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="shiroRealm" />
    </bean>

    <!--Shiro核心过滤器-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- Shiro的核心安全接口,这个属性是必须的 -->
        <property name="securityManager" ref="securityManager" />
        <!-- 身份验证失败,跳转到登录页面 -->
        <property name="loginUrl" value="/login"/>
        <!-- 身份验证成功,跳转到指定页面 -->
        <!--<property name="successUrl" value="/index.jsp"/>-->
        <!-- 权限验证失败,跳转到指定页面 -->
        <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
        <!-- Shiro连接约束配置,即过滤链的定义 -->
        <property name="filterChainDefinitions">
            <value>
                <!--
                注:anon,authcBasic,auchc,user是认证过滤器
                    perms,roles,ssl,rest,port是授权过滤器
                -->
                <!--anon 表示匿名访问,不需要认证以及授权-->
                <!--authc表示需要认证 没有进行身份认证是不能进行访问的-->
                <!--roles[admin]表示角色认证,必须是拥有admin角色的用户才行-->
                /user/login=anon
                /user/updatePwd.jsp=authc
                /admin/*.jsp=roles[admin]
                /user/teacher.jsp=perms["user:update"]
                <!-- /css/**               = anon
                 /images/**            = anon
                 /js/**                = anon
                 /                     = anon
                 /user/logout          = logout
                 /user/**              = anon
                 /userInfo/**          = authc
                 /dict/**              = authc
                 /console/**           = roles[admin]
                 /**                   = anon-->
            </value>
        </property>
    </bean>

    <!-- Shiro生命周期,保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>

Add in applicationContext.xml:

<!--整合shiro-->
    <import resource="applicationContext-shiro.xml"></import>

2. Salt encryption (MD5)

Salt encryption tools are used when adding new users. Put the encrypted password and the encrypted salt into the database;
the table data in this blog is ready-made, and this tool is temporarily not available to generate data ;

The first step: the tool PasswordHelper.java

package com.xiaoqing.ssm.utils;

import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;

public class PasswordHelper {
    
    

    /**
     * 随机数生成器
     */
    private static RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();

    /**
     * 指定hash算法为MD5
     */
    private static final String hashAlgorithmName = "md5";

    /**
     * 指定散列次数为1024次,即加密1024次
     */
    private static final int hashIterations = 1024;

    /**
     * true指定Hash散列值使用Hex加密存. false表明hash散列值用用Base64-encoded存储
     */
    private static final boolean storedCredentialsHexEncoded = true;

    /**
     * 获得加密用的盐
     *
     * @return
     */
    public static String createSalt() {
    
    
        return randomNumberGenerator.nextBytes().toHex();
    }

    /**
     * 获得加密后的凭证
     *
     * @param credentials 凭证(即密码)
     * @param salt        盐
     * @return
     */
    public static String createCredentials(String credentials, String salt) {
    
    
        SimpleHash simpleHash = new SimpleHash(hashAlgorithmName, credentials,
                salt, hashIterations);
        return storedCredentialsHexEncoded ? simpleHash.toHex() : simpleHash.toBase64();
    }


    /**
     * 进行密码验证
     *
     * @param credentials        未加密的密码
     * @param salt               盐
     * @param encryptCredentials 加密后的密码
     * @return
     */
    public static boolean checkCredentials(String credentials, String salt, String encryptCredentials) {
    
    
        return encryptCredentials.equals(createCredentials(credentials, salt));
    }

    public static void main(String[] args) {
    
    
        //盐
        String salt = createSalt();
        System.out.println(salt);
        System.out.println(salt.length());
        //凭证+盐加密后得到的密码
        String credentials = createCredentials("123", salt);
        System.out.println(credentials);
        System.out.println(credentials.length());
        boolean b = checkCredentials("123", salt, credentials);
        System.out.println(b);
    }
}

Insert picture description here

3.shiro certification test

The first step: MyRealm.java:

package com.xiaoqing.ssm.shiro;

import com.xiaoqing.ssm.model.ShiroUser;
import com.xiaoqing.ssm.service.ShiroUserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author 晴sister
 * @site https://blog.csdn.net/men_ma
 * @company
 * @create 2020-10-289:19
 *
 *
 * 这个类替换掉了上堂课的ini文件,所有用户的身份都从这里来
 *
 *
 *
 *
 * shiro入门七步走
 *  * 1、将数据源realm读取到安全管理器securityManagerfactory
 *  * 2、securityManagerfactory创建出安全管理器实例securityManager
 *  * 3、将securityManager交给securityUtil
 *
 *    前三步web.xml配置监听器已经帮你完成
 *
 *  * 4、securityUtil获取登录主体subject
 *  * 5、从jsp获取到用户名密码然后将其组装成登录令牌token
 *  * 6、subject去使用令牌token进行登录
 *  * 7、登录可能成功,也可能失败,那么需要对登录的结果进行处理
 *  *
 */
public class MyRealm extends AuthorizingRealm {
    
    
    private ShiroUserService shiroUserService;

    public ShiroUserService getShiroUserService() {
    
    
        return shiroUserService;
    }

    public void setShiroUserService(ShiroUserService shiroUserService) {
    
    
        this.shiroUserService = shiroUserService;
    }

    /**
     * 授权的方法
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
    
        return null;
    }

    /**
     * 身份认证的方法
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    
    
//        获取身份(Principal)
        String uname=authenticationToken.getPrincipal().toString();
//        获取凭证/密码(Credentials)
        String pwd=authenticationToken.getCredentials().toString();
//        调用方法
        ShiroUser shiroUser = shiroUserService.queryByName(uname);

        /**
         * 第一个参数:principal(身份)
         * 第二个参数:hashedCredentials(凭证)
         * 第三个参数:credentialsSalt(凭证盐)
         * 第四个参数:realmName(realm的名字)
         */
        AuthenticationInfo info =new SimpleAuthenticationInfo(
                shiroUser.getUsername(),
                shiroUser.getPassword(),
                ByteSource.Util.bytes(shiroUser.getSalt()),
//                this代表类名,类对象的实例MyRealm
                this.getName()
        );
        return info;
    }
}

Step 2: Import the JSP used in the previous blog (the code is in the previous blog)

Insert picture description here

The third step: ShiroUserController.java (control layer)

package com.xiaoqing.ssm.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;

/**
 * @author 晴sister
 * @site https://blog.csdn.net/men_ma
 * @company
 * @create 2020-10-290:30
 */
@Controller
public class ShiroUserController {
    
    

    /**
     * 登录
     * @param req
     * @return
     */
    @RequestMapping("/login")
    public String login(HttpServletRequest req){
    
    
        Subject subject = SecurityUtils.getSubject();
        String uname=req.getParameter("username");
        String pwd=req.getParameter("password");
        UsernamePasswordToken token=new UsernamePasswordToken(uname,pwd);

        try {
    
    
//            这里会跳转到MyRealm中的认证方法
            subject.login(token);
            req.getSession().setAttribute("username",uname);
            return "main";
        }catch (Exception e){
    
    
            req.setAttribute("message","用户名密码错误!!!!");
            return "login";
        }
    }

    /**
     * 退出
     * @param req
     * @return
     */
    @RequestMapping("/logout")
    public String logout(HttpServletRequest req){
    
    
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "redirect:/login.jsp";
    }
}

Step 4: Test and see the results

Shiro completes the process of identity authentication: jsp—>controller—>subject.login—>MyRealm.authentication

zs account login:
Insert picture description here
Insert picture description here

Insert picture description here

Insert picture description here
Insert picture description here

zdm account login:
Insert picture description here
Insert picture description here

Guess you like

Origin blog.csdn.net/men_ma/article/details/109350919