• shiro认证+盐加密


    Shiro认证

    导入pom依赖

    <shiro.version>1.2.5</shiro.version>
     1 <!--shiro-->
     2         <dependency>
     3             <groupId>org.apache.shiro</groupId>
     4             <artifactId>shiro-core</artifactId>
     5             <version>${shiro.version}</version>
     6         </dependency>
     7 
     8         <dependency>
     9             <groupId>org.apache.shiro</groupId>
    10             <artifactId>shiro-web</artifactId>
    11             <version>${shiro.version}</version>
    12         </dependency>
    13 
    14         <dependency>
    15             <groupId>org.apache.shiro</groupId>
    16             <artifactId>shiro-spring</artifactId>
    17             <version>${shiro.version}</version>
    18         </dependency>

    配置web.xml

     1  <!-- shiro过滤器定义 -->
     2   <filter>
     3     <filter-name>shiroFilter</filter-name>
     4     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
     5     <init-param>
     6       <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
     7       <param-name>targetFilterLifecycle</param-name>
     8       <param-value>true</param-value>
     9     </init-param>
    10   </filter>
    11   <filter-mapping>
    12     <filter-name>shiroFilter</filter-name>
    13     <url-pattern>/*</url-pattern>
    14   </filter-mapping>

    通过逆向将数据库表生成对应的model、mapper类

    这里就不一一展示生成的结果了。

    主要看一下需要用到的ShiroUserMapper和ShiroUserMapper.xml

    ShiroUserMapper

     1 package com.yuan.mapper;
     2 
     3 import com.yuan.model.ShiroUser;
     4 import org.apache.ibatis.annotations.Param;
     5 import org.springframework.stereotype.Repository;
     6 
     7 @Repository
     8 public interface ShiroUserMapper {
     9     int deleteByPrimaryKey(Integer userid);
    10 
    11     int insert(ShiroUser record);
    12 
    13     int insertSelective(ShiroUser record);
    14 
    15     ShiroUser selectByPrimaryKey(Integer userid);
    16 
    17     int updateByPrimaryKeySelective(ShiroUser record);
    18 
    19     int updateByPrimaryKey(ShiroUser record);
    20 
    21     ShiroUser queryByName(@Param("uname")String uname);
    22 
    23 }

    ShiroUserMapper.xml

      1 <?xml version="1.0" encoding="UTF-8" ?>
      2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
      3 <mapper namespace="com.yuan.mapper.ShiroUserMapper" >
      4   <resultMap id="BaseResultMap" type="com.yuan.model.ShiroUser" >
      5     <constructor >
      6       <idArg column="userid" jdbcType="INTEGER" javaType="java.lang.Integer" />
      7       <arg column="username" jdbcType="VARCHAR" javaType="java.lang.String" />
      8       <arg column="PASSWORD" jdbcType="VARCHAR" javaType="java.lang.String" />
      9       <arg column="salt" jdbcType="VARCHAR" javaType="java.lang.String" />
     10       <arg column="createdate" jdbcType="TIMESTAMP" javaType="java.util.Date" />
     11     </constructor>
     12   </resultMap>
     13   <sql id="Base_Column_List" >
     14     userid, username, PASSWORD, salt, createdate
     15   </sql>
     16   <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
     17     select 
     18     <include refid="Base_Column_List" />
     19     from t_shiro_user
     20     where userid = #{userid,jdbcType=INTEGER}
     21   </select>
     22   <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
     23     delete from t_shiro_user
     24     where userid = #{userid,jdbcType=INTEGER}
     25   </delete>
     26   <insert id="insert" parameterType="com.yuan.model.ShiroUser" >
     27     insert into t_shiro_user (userid, username, PASSWORD, 
     28       salt, createdate)
     29     values (#{userid,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, 
     30       #{salt,jdbcType=VARCHAR}, #{createdate,jdbcType=TIMESTAMP})
     31   </insert>
     32   <insert id="insertSelective" parameterType="com.yuan.model.ShiroUser" >
     33     insert into t_shiro_user
     34     <trim prefix="(" suffix=")" suffixOverrides="," >
     35       <if test="userid != null" >
     36         userid,
     37       </if>
     38       <if test="username != null" >
     39         username,
     40       </if>
     41       <if test="password != null" >
     42         PASSWORD,
     43       </if>
     44       <if test="salt != null" >
     45         salt,
     46       </if>
     47       <if test="createdate != null" >
     48         createdate,
     49       </if>
     50     </trim>
     51     <trim prefix="values (" suffix=")" suffixOverrides="," >
     52       <if test="userid != null" >
     53         #{userid,jdbcType=INTEGER},
     54       </if>
     55       <if test="username != null" >
     56         #{username,jdbcType=VARCHAR},
     57       </if>
     58       <if test="password != null" >
     59         #{password,jdbcType=VARCHAR},
     60       </if>
     61       <if test="salt != null" >
     62         #{salt,jdbcType=VARCHAR},
     63       </if>
     64       <if test="createdate != null" >
     65         #{createdate,jdbcType=TIMESTAMP},
     66       </if>
     67     </trim>
     68   </insert>
     69   <update id="updateByPrimaryKeySelective" parameterType="com.yuan.model.ShiroUser" >
     70     update t_shiro_user
     71     <set >
     72       <if test="username != null" >
     73         username = #{username,jdbcType=VARCHAR},
     74       </if>
     75       <if test="password != null" >
     76         PASSWORD = #{password,jdbcType=VARCHAR},
     77       </if>
     78       <if test="salt != null" >
     79         salt = #{salt,jdbcType=VARCHAR},
     80       </if>
     81       <if test="createdate != null" >
     82         createdate = #{createdate,jdbcType=TIMESTAMP},
     83       </if>
     84     </set>
     85     where userid = #{userid,jdbcType=INTEGER}
     86   </update>
     87   <update id="updateByPrimaryKey" parameterType="com.yuan.model.ShiroUser" >
     88     update t_shiro_user
     89     set username = #{username,jdbcType=VARCHAR},
     90       PASSWORD = #{password,jdbcType=VARCHAR},
     91       salt = #{salt,jdbcType=VARCHAR},
     92       createdate = #{createdate,jdbcType=TIMESTAMP}
     93     where userid = #{userid,jdbcType=INTEGER}
     94   </update>
     95 
     96   <select id="queryByName" resultType="com.yuan.model.ShiroUser" parameterType="java.lang.String" >
     97     select
     98     <include refid="Base_Column_List" />
     99     from t_shiro_user
    100     where username = #{uname}
    101   </select>
    102 
    103 
    104 </mapper>

    Service层

     1 package com.yuan.service;
     2 
     3 import com.yuan.model.ShiroUser;
     4 import org.apache.ibatis.annotations.Param;
     5 
     6 public interface ShiroUserService {
     7 
     8     ShiroUser queryByName(@Param("uname")String uname);
     9 
    10     int insert(ShiroUser record);
    11 
    12 }

    Service实现类

    package com.yuan.service.impl;
    
    import com.yuan.mapper.ShiroUserMapper;
    import com.yuan.model.ShiroUser;
    import com.yuan.service.ShiroUserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service("shiroUserService")
    public class ShiroUserServiceImpl implements ShiroUserService {
        @Autowired
        private ShiroUserMapper shiroUserMapper;
    
        @Override
        public ShiroUser queryByName(String uname) {
            return shiroUserMapper.queryByName(uname);
        }
    
        @Override
        public int insert(ShiroUser record) {
            return shiroUserMapper.insert(record);
        }
    }

    MyRealm

     1 package com.yuan.shiro;
     2 
     3 import com.yuan.mapper.ShiroUserMapper;
     4 import com.yuan.model.ShiroUser;
     5 import com.yuan.service.ShiroUserService;
     6 import lombok.ToString;
     7 import org.apache.shiro.authc.AuthenticationException;
     8 import org.apache.shiro.authc.AuthenticationInfo;
     9 import org.apache.shiro.authc.AuthenticationToken;
    10 import org.apache.shiro.authc.SimpleAuthenticationInfo;
    11 import org.apache.shiro.authz.AuthorizationInfo;
    12 import org.apache.shiro.realm.AuthorizingRealm;
    13 import org.apache.shiro.subject.PrincipalCollection;
    14 import org.apache.shiro.util.ByteSource;
    15 import org.springframework.stereotype.Component;
    16 
    17 
    18 /*
    19 替换掉.ini的文件,所有用户的身份数据源
    20  */
    21 public class MyRealm extends AuthorizingRealm {
    22     private ShiroUserService shiroUserService;
    23 
    24     public ShiroUserService getShiroUserService() {
    25         return shiroUserService;
    26     }
    27 
    28     public void setShiroUserService(ShiroUserService shiroUserService) {
    29         this.shiroUserService = shiroUserService;
    30     }
    31 
    32     /*
    33         授权的方法
    34          */
    35     @Override
    36     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    37         return null;
    38     }
    39 
    40     /*
    41     身份认证的方法
    42      */
    43     @Override
    44     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    45         String uname = authenticationToken.getPrincipal().toString();
    46         String pwd = authenticationToken.getCredentials().toString();
    47         ShiroUser shiroUser = shiroUserService.queryByName(uname);
    48 
    49         AuthenticationInfo info = new SimpleAuthenticationInfo(
    50                 shiroUser.getUsername(),
    51                 shiroUser.getPassword(),
    52                 ByteSource.Util.bytes(shiroUser.getSalt()),
    53                 this.getName()
    54                 );
    55 
    56         return info;
    57     }
    58 
    59 }
    applicationContext-shiro.xml
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
     5 
     6     <!--配置自定义的Realm-->
     7     <bean id="shiroRealm" class="com.yuan.shiro.MyRealm">
     8         <property name="shiroUserService" ref="shiroUserService" />
     9         <!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
    10         <!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
    11         <!--注意:重要的事情说三次~~~~~~此处加密方式要与用户注册时的算法一致 -->
    12         <!--以下三个配置告诉shiro将如何对用户传来的明文密码进行加密-->
    13         <property name="credentialsMatcher">
    14             <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    15                 <!--指定hash算法为MD5-->
    16                 <property name="hashAlgorithmName" value="md5"/>
    17                 <!--指定散列次数为1024次-->
    18                 <property name="hashIterations" value="1024"/>
    19                 <!--true指定Hash散列值使用Hex加密存. false表明hash散列值用用Base64-encoded存储-->
    20                 <property name="storedCredentialsHexEncoded" value="true"/>
    21             </bean>
    22         </property>
    23     </bean>
    24 
    25     <!--注册安全管理器-->
    26     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    27         <property name="realm" ref="shiroRealm" />
    28     </bean>
    29 
    30     <!--Shiro核心过滤器-->
    31     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    32         <!-- Shiro的核心安全接口,这个属性是必须的 -->
    33         <property name="securityManager" ref="securityManager" />
    34         <!-- 身份验证失败,跳转到登录页面 -->
    35         <property name="loginUrl" value="/login"/>
    36         <!-- 身份验证成功,跳转到指定页面 -->
    37         <!--<property name="successUrl" value="/index.jsp"/>-->
    38         <!-- 权限验证失败,跳转到指定页面 -->
    39         <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
    40         <!-- Shiro连接约束配置,即过滤链的定义 -->
    41         <property name="filterChainDefinitions">
    42             <value>
    43                 <!--
    44                 注:anon,authcBasic,auchc,user是认证过滤器
    45                     perms,roles,ssl,rest,port是授权过滤器
    46                 -->
    47                 <!--anon 表示匿名访问,不需要认证以及授权-->
    48                 <!--authc表示需要认证 没有进行身份认证是不能进行访问的-->
    49                 <!--roles[admin]表示角色认证,必须是拥有admin角色的用户才行-->
    50                 /user/login=anon
    51                 /user/updatePwd.jsp=authc
    52                 /admin/*.jsp=roles[admin]
    53                 /user/teacher.jsp=perms["user:update"]
    54                 <!-- /css/**               = anon
    55                  /images/**            = anon
    56                  /js/**                = anon
    57                  /                     = anon
    58                  /user/logout          = logout
    59                  /user/**              = anon
    60                  /userInfo/**          = authc
    61                  /dict/**              = authc
    62                  /console/**           = roles[admin]
    63                  /**                   = anon-->
    64             </value>
    65         </property>
    66     </bean>
    67 
    68     <!-- Shiro生命周期,保证实现了Shiro内部lifecycle函数的bean执行 -->
    69     <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    70 </beans>

    ShiroUserController

     1 package com.yuan.controller;
     2 
     3 
     4 import com.yuan.model.ShiroUser;
     5 import com.yuan.service.ShiroUserService;
     6 import com.yuan.util.PasswordHelper;
     7 import org.apache.shiro.SecurityUtils;
     8 import org.apache.shiro.authc.AuthenticationException;
     9 import org.apache.shiro.authc.UsernamePasswordToken;
    10 import org.apache.shiro.subject.Subject;
    11 import org.springframework.beans.factory.annotation.Autowired;
    12 import org.springframework.stereotype.Controller;
    13 import org.springframework.web.bind.annotation.RequestMapping;
    14 
    15 import javax.servlet.http.HttpServletRequest;
    16 import javax.servlet.http.HttpServletResponse;
    17 
    18 @Controller
    19 public class ShiroUserController {
    20 
    21     @Autowired
    22     private ShiroUserService shiroUserService;
    23 
    24 
    25     /*
    26     用户登录
    27      */
    28     @RequestMapping("/login")
    29     public String login(HttpServletRequest req){
    30         Subject subject = SecurityUtils.getSubject();
    31         String uname = req.getParameter("username");
    32         String pwd = req.getParameter("password");
    33         UsernamePasswordToken token = new UsernamePasswordToken(uname, pwd);
    34 
    35         try {
    36 //            这里会跳转到MyRealm中的认证方法
    37             subject.login(token);
    38             req.getSession().setAttribute("username", uname);
    39             return "main";
    40 
    41         } catch (AuthenticationException e) {
    42             req.setAttribute("message","用户名或密码错误!!!");
    43             return "login";
    44         }
    45 
    46     }
    47 
    48     /*
    49     退出登录
    50      */
    51     @RequestMapping("/logout")
    52     public String logout(HttpServletRequest req) {
    53         Subject subject = SecurityUtils.getSubject();
    54         subject.logout();
    55         return "redirect:/login.jsp";
    56     }
    57 
    58 
    59     /*
    60     用户注册
    61      */
    62     @RequestMapping("/register")
    63     public String register(HttpServletRequest req, HttpServletResponse resp){
    64         String uname = req.getParameter("username");
    65         String pwd = req.getParameter("password");
    66         String salt = PasswordHelper.createSalt();
    67         String credentials = PasswordHelper.createCredentials(pwd, salt);
    68 
    69         ShiroUser shiroUser=new ShiroUser();
    70         shiroUser.setUsername(uname);
    71         shiroUser.setPassword(credentials);
    72         shiroUser.setSalt(salt);
    73         int insert = shiroUserService.insert(shiroUser);
    74         if(insert>0){
    75             req.setAttribute("message","注册成功");
    76             return "login";
    77         }
    78         else{
    79             req.setAttribute("message","注册失败");
    80             return "register";
    81         }
    82 }
    83 
    84 
    85 
    86 }

    盐加密的工具类

    PasswordHelper

     1 package com.yuan.util;
     2 
     3 import org.apache.shiro.crypto.RandomNumberGenerator;
     4 import org.apache.shiro.crypto.SecureRandomNumberGenerator;
     5 import org.apache.shiro.crypto.hash.SimpleHash;
     6 
     7 public class PasswordHelper {
     8 
     9     /**
    10      * 随机数生成器
    11      */
    12     private static RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
    13 
    14     /**
    15      * 指定hash算法为MD5
    16      */
    17     private static final String hashAlgorithmName = "md5";
    18 
    19     /**
    20      * 指定散列次数为1024次,即加密1024次
    21      */
    22     private static final int hashIterations = 1024;
    23 
    24     /**
    25      * true指定Hash散列值使用Hex加密存. false表明hash散列值用用Base64-encoded存储
    26      */
    27     private static final boolean storedCredentialsHexEncoded = true;
    28 
    29     /**
    30      * 获得加密用的盐
    31      *
    32      * @return
    33      */
    34     public static String createSalt() {
    35         return randomNumberGenerator.nextBytes().toHex();
    36     }
    37 
    38     /**
    39      * 获得加密后的凭证
    40      *
    41      * @param credentials 凭证(即密码)
    42      * @param salt        盐
    43      * @return
    44      */
    45     public static String createCredentials(String credentials, String salt) {
    46         SimpleHash simpleHash = new SimpleHash(hashAlgorithmName, credentials,
    47                 salt, hashIterations);
    48         return storedCredentialsHexEncoded ? simpleHash.toHex() : simpleHash.toBase64();
    49     }
    50 
    51 
    52     /**
    53      * 进行密码验证
    54      *
    55      * @param credentials        未加密的密码
    56      * @param salt               盐
    57      * @param encryptCredentials 加密后的密码
    58      * @return
    59      */
    60     public static boolean checkCredentials(String credentials, String salt, String encryptCredentials) {
    61         return encryptCredentials.equals(createCredentials(credentials, salt));
    62     }
    63 
    64     public static void main(String[] args) {
    65         //
    66         String salt = createSalt();
    67         System.out.println(salt);
    68         System.out.println(salt.length());
    69         //凭证+盐加密后得到的密码
    70         String credentials = createCredentials("123", salt);
    71         System.out.println(credentials);
    72         System.out.println(credentials.length());
    73         boolean b = checkCredentials("123", salt, credentials);
    74         System.out.println(b);
    75     }
    76 }

    Jsp页面

    login.jsp

     1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
     2 <html>
     3 <head>
     4     <title>Title</title>
     5 </head>
     6 <body>
     7     <h1>用户登陆</h1>
     8     <div style="color: red">${message}</div>
     9     <form action="${pageContext.request.contextPath}/login" method="post">
    10         帐号:<input type="text" name="username"><br>
    11         密码:<input type="password" name="password"><br>
    12         <input type="submit" value="确定">
    13         <input type="reset" value="重置">
    14     </form>
    15 </body>
    16 </html>

    register.jsp

     1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
     2 <html>
     3 <head>
     4     <title>Title</title>
     5 </head>
     6 <body>
     7 <h1>用户注册</h1>
     8 <div style="color: red">${message}</div>
     9 <form action="${pageContext.request.contextPath}/register" method="post">
    10     帐号:<input type="text" name="username"><br>
    11     密码:<input type="password" name="password"><br>
    12     <input type="submit" value="注册">
    13     <input type="button" οnclick="location.href='${pageContext.request.contextPath}/login.jsp'" value="返回">
    14 </form>
    15 </body>
    16 </html>

    main.jsp

     1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
     2 <%@taglib prefix="r" uri="http://shiro.apache.org/tags" %>
     3 <html>
     4 <head>
     5     <title>Title</title>
     6 </head>
     7 <body>
     8 <h1>主界面<%=System.currentTimeMillis()%>,欢迎您:[${sessionScope.username}]</h1>
     9 <ul>
    10     系统功能列表
    11     <li>
    12         <a href="admin/addUser.jsp">用户新增</a>
    13     </li>
    14     <li>
    15         <a href="admin/listUser.jsp">用户查询</a>
    16     </li>
    17     <li>
    18         <a href="admin/resetPwd.jsp">重置用户密码</a>
    19     </li>
    20     <li>
    21         <a href="admin/updateUser.jsp">用户修改</a>
    22     </li>
    23     <li>
    24         <a href="user/updatePwd.jsp">个人密码修改</a>
    25     </li>
    26     <li>
    27         <a href="user/teacher.jsp">老师简介</a>
    28     </li>
    29     <li>
    30         <a href="${pageContext.request.contextPath}/logout">退出系统</a>
    31     </li>
    32 </ul>
    33 <ul>
    34     shiro标签
    35     <li>
    36         <r:hasPermission name="user:create">
    37             <a href="admin/addUser.jsp">用户新增</a>
    38         </r:hasPermission>
    39     </li>
    40     <li>
    41         <a href="admin/listUser.jsp">用户查询</a>
    42     </li>
    43     <li>
    44         <a href="admin/resetPwd.jsp">重置用户密码</a>
    45     </li>
    46     <li>
    47         <r:hasPermission name="user:update">
    48             <a href="admin/updateUser.jsp">用户修改</a>
    49         </r:hasPermission>
    50     </li>
    51     <li>
    52         <a href="user/updatePwd.jsp">个人密码修改</a>
    53     </li>
    54     <li>
    55         <a href="${pageContext.request.contextPath}/logout">退出系统</a>
    56     </li>
    57 </ul>
    58 </body>
    59 </html>

    运行结果

    谢谢观看!!!

  • 相关阅读:
    jQuery常用事件,each循环,引用当前时间
    jQuery查找标签和操作标签
    PhaseScorer:感慨高手写的代码就是精炼
    遍历倒排索引核心类:SegmentTermDocs/SegmentTermPositions
    Lucene搜索核心代码TermInfosReader
    Lucene BooleanQuery相关算法
    Lucene搜索/索引过程笔记
    Lucene queryParser和analysis有什么不同?
    Lucene为什么要加Segment概念
    Lucene 写入一个文档到该文档可搜索延迟是多少?
  • 原文地址:https://www.cnblogs.com/ly-0919/p/11790030.html
Copyright © 2020-2023  润新知