Shiro加密认证

使用Shiro完成用户认证

环境:MyEclipse2017、JDK1.7、Spring4.1
步骤:

  • 创建WEB项目添加Spring4.1支持并配置SpringMVC
  • 引入Shiro相关jar包
  • 编写Realm
  • 配置Shiro前端过滤器
  • 配置安全管理器及Shiro过滤器
  • 编写Controller进行测试

步骤一:创建WEB项目添加Spring4.1支持并配置SpringMVC

此处大约省略了有一万字。。。。。。

步骤二:引入Shiro相关jar包

     shiro-all-1.2.3.jar
     slf4j-api-1.7.25.jar
     slf4j-log4j12-1.7.25.jar 

步骤三:编写Realm

package com.hcq.bean;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

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.authc.UsernamePasswordToken;
import org.apache.shiro.realm.AuthenticatingRealm;
//Realm:访问数据库
public class Realm extends AuthenticatingRealm{
    /*
     * 1.doGetAuthenticationInfo方法:获取认证信息,进行认证
     * 
     * 2.AuthenticationInfo接口:可以使用SimpleAuthenticationInfo实现类,封装数据库中用户信息
     * 
     * 3.AuthenticationToken参数:封装用户输入的认证信息
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken Token=(UsernamePasswordToken)token;//认证信息
        String principal=Token.getUsername();
        String realmName=this.getName();
        //查询一波数据库
        try {
            Class.forName("com.mysql.jdbc.Driver");
            Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/first","root", "root");
              PreparedStatement pstm=conn.prepareStatement("select password from user where name=?");
              pstm.setString(1, principal);
            ResultSet rs=pstm.executeQuery();
            if(rs.next()){
                String credentials=rs.getString(1);
                //将数据库中查询到的info返回用于匹配认证信息。参数:(用户名,用户密码,Realm名称)
                SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(principal, credentials, realmName);
               return info;
            }else{
                throw new RuntimeException("用户不存在");
            }
        } catch (Exception e) {
            System.out.println("数据库链接异常");
            e.printStackTrace();
        }

        return null;
    }

}

步骤四:配置Shiro前端过滤器
此处为了便于管理,我将Shiro同SpringMVC一样单独配置在一个xml中,这个xml名为“shiro-config.xml”,并且在第12行将此配置文件注册到了上下文中(也可以直接在Spring容器中进行配置)。由下面的配置信息可知Shiro的前端控制器是一个过滤器org.springframework.web.filter.DelegatingFilterProxy
web.xml配置如下

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
  <display-name>ShiroTest</display-name>
  <!-- Spring IOC容器 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      classpath:applicationContext.xml
      classpath:shiro-config.xml
    </param-value>
  </context-param>
  <!-- Spring MVC -->
  <servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  <!--Shiro-->
   <filter>
     <filter-name>ShiroFilter</filter-name>
     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
   </filter>
   <filter-mapping>
     <filter-name>ShiroFilter</filter-name>
     <url-pattern>/*</url-pattern>
   </filter-mapping>
</web-app>

步骤五:配置安全管理器及Shiro过滤器
创建一个配置信息如下的shiro-config.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"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
    ">
      <!-- 配置安全管理器 -->
      <bean class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" id="securityManager">
         <property name="realm" ref="AuRealm"/>
      </bean>    
      <!-- Realm -->
      <bean id="AuRealm" class="com.hcq.bean.Realm"></bean>
      <!-- 配置Shiro过滤器 -->
      <bean id="ShiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
       <property name="securityManager" ref="securityManager"/>
       <property name="loginUrl" value="/index.jsp"/><!--未登录时跳转的页面-->
       <property name="unauthorizedUrl" value="/Error.jsp"/><!--权限不足所跳转的页面-->
         <!-- 定义过滤链 -->
          <property name="filterChainDefinitions">  
           <value>  
              /index.jsp=anon<!--可以匿名访问-->
              /hello.action=anon
              /logout=logout<!--注销-->
             /**=authc<!--需要进行过滤的请求-->
           </value>  
         </property>
      </bean>
</beans>

步骤六:编写Controller进行测试

package com.hcq.controller;

@Controller
public class Test {

   @RequestMapping("hello")
   public String hello(String name,String password){
       Subject user=SecurityUtils.getSubject();//封装用户信息
            if(!user.isAuthenticated()){//判断用户认证状态
                UsernamePasswordToken token = new UsernamePasswordToken(name, password);//封装认证信息
                try {
                    user.login(token);//执行认证
                    System.out.println("认证成功!");
                } catch (Exception e) {
                    System.out.println("认证失败!");
                }
            }else{
                System.out.println("用户已认证!");
            }
           return "Home";
   }
}

Shiro加密认证

在数据中,存储的都是经过加密后的用户密码,如果Shiro认证不加密,那么用户认证时所输入的明文将会与数据库中的不匹配,所以我们需要把用户输入的明文加密后再与数据库进行匹配。Shiro中加密认证非常简单,只需要在Realm中将Realm添加一个加密器的属性即可。
更改后的Realm配置如下

      <bean id="AuRealm" class="com.hcq.bean.Realm">
         <property name="credentialsMatcher">
             <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
               <property name="hashAlgorithmName" value="MD5"/><!--加密方式-->
               <property name="hashIterations" value="1024"/><!--加密次数-->
             </bean>
         </property>
      </bean>

添加加密器后,当用户调用subject.login方法时,Shiro底层会将UsernamePasswordToken中用户输入的明文进行加密,然后在数据库中进行匹配,匹配失败会产生对应异常。
盐值加密
为了进一步提高数据的安全性,在Shiro中可以通过盐值加密,对相同密码而产生唯一的密文。就像现实生活中的西红柿炒鸡蛋,食材都是西红柿+鸡蛋却可以因为调料的不同而产生不同的味道。

                 //普通加密认证
                SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(principal, credentials, realmName);
                 //盐值加密
                ByteSource salt=ByteSource.Util.bytes(principal);//盐:principal
                info=new SimpleAuthenticationInfo(principal, credentials, salt, realmName);

由上面的代码段可以看到,盐值加密认证就比普通加密认证多了一个ByteSource参数,而这个参数一般为数据库中的主键。总结一下就是:通过主键的唯一性从而产生不同的密文。

猜你喜欢

转载自blog.csdn.net/qq_39914581/article/details/81128090