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>

 

运行结果

 

 

谢谢观看!!!

 

posted @ 2019-11-04 00:13  Me*源  阅读(528)  评论(0编辑  收藏  举报