• Shiro认证-SSM


    目标

    一、盐加密

    继续在之前的ssm项目上续写

    (一)Shiro环境配置与表生成

    1、导入pom相关依赖

    
                org.apache.shiro
                shiro-core
                1.3.2
            
    
            
                org.apache.shiro
                shiro-web
                1.3.2
            
    
            
                org.apache.shiro
                shiro-spring
                1.3.2
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2、web.xml配置

     
      
        shiroFilter
        org.springframework.web.filter.DelegatingFilterProxy
        
          
          targetFilterLifecycle
          true
        
      
      
        shiroFilter
        /*
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3、通过逆向工程将五张表生成对应的model、mapper

    ①、generatorConfig.xml

     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    ②、检查是否生成在ssm下面:

    之后运行就可以了

    4、增加通过账号查询用户信息的方法

    ①、ShiroUserMapper.xml:

    
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ②、ShiroUserMapper:

    定义对应的方法
    public ShiroUser queryByName(@Param(“userName”) String userName);

    ③、ShiroUserService

    package com.lsy.service;
    
    import com.lsy.model.ShiroUser;
    import org.apache.ibatis.annotations.Param;
    
    public interface ShiroUserService {
        int deleteByPrimaryKey(Integer userid);
    
        int insert(ShiroUser record);
    
        int insertSelective(ShiroUser record);
    
        ShiroUser selectByPrimaryKey(Integer userid);
    
        int updateByPrimaryKeySelective(ShiroUser record);
    
        int updateByPrimaryKey(ShiroUser record);
    
        public ShiroUser queryByName(String userName);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    ④、ShiroUserServiceImpl 实现ShiroUserService接口

    package com.lsy.service.impl;
    
    import com.lsy.mapper.ShiroUserMapper;
    import com.lsy.model.ShiroUser;
    import com.lsy.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 int deleteByPrimaryKey(Integer userid) {
            return 0;
        }
    
        @Override
        public int insert(ShiroUser record) {
            return 0;
        }
    
        @Override
        public int insertSelective(ShiroUser record) {
            return 0;
        }
    
        @Override
        public ShiroUser selectByPrimaryKey(Integer userid) {
            return null;
        }
    
        @Override
        public int updateByPrimaryKeySelective(ShiroUser record) {
            return 0;
        }
    
        @Override
        public int updateByPrimaryKey(ShiroUser record) {
            return 0;
        }
    
        @Override
        public ShiroUser queryByName(String userName) {
            return shiroUserMapper.queryByName(userName);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    md5解密:

    md5的缺陷:有破解工具,安全系数降低,

    明文与密文一一对应的关系,明文加密成固定的密文;

    Shiro加密

    盐加密工具类,在做新增用户的时候使用,将加密后的密码、及加密时候的盐放入数据库;

    本篇博客中的表数据是现成的,暂时用不上这个工具类去生成数据;

    1、PasswordHelper(util包下) :

    密码工具类,加密1024次不能透露·,透露也就不安全了(因为一个明文对应一个密文,不断反推依旧能推出)

    package com.lsy.util;
    
    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    2、运行获得结果

    第一次运行:

    第二次运行:

    两次运行的结果都不相同,但同时都是123;安全系数高

    二、Shiro认证

    **1、**Myrealm.java

    自定义Realm
    Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。

    最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权。

    通常自定义的realm继承AuthorizingRealm

    注1:体系结构见“shiro提供的realm.png”

    AuthorizationInfo:授权信息
    AuthenticationInfo:认证信息

    **继承AuthorizingRealm需要重写两个方法;**重写授权与认证

    package com.lsy.shiro;
    
    import com.lsy.model.ShiroUser;
    import com.lsy.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.stereotype.Service;
    
    /**
     * @author 小李飞刀
     * @site www.javaxl.com
     * @company
     * @create? 2019-10-12 16:20
     *
     * com.lsy.shiro.MyRealm需要在applicationcontext-shiro.xml配置
     */
    
    
    public class MyRealm extends AuthorizingRealm {
        private ShiroUserService shiroUserService;
    
        public ShiroUserService getShiroUserService() {
    
            return shiroUserService;
        }
    
        public void setShiroUserService(ShiroUserService shiroUserService) {
    
            this.shiroUserService = shiroUserService;
        }
    
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            return null;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("身份认证...");
            //token就是controller层中的login请求,subject.login(token)
            String username = token.getPrincipal().toString();
            String password = token.getCredentials().toString();
            ShiroUser user = shiroUserService.queryByName(username);
    //        拿到数据库中的用户信息,放入token凭证中,用于controler进行对比
            AuthenticationInfo info = new SimpleAuthenticationInfo(
                    user.getUsername(),
                    user.getPassword(),
                    ByteSource.Util.bytes(user.getSalt()),
                    this.getName()
            );
            return info;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    2、applicationContext-shiro.xml

    MyRealm要交给spring进行管理需要在applicationContext-shiro.xml中进行配置

    
    
    
        
        
            
            
            
            
            
            
                
                    
                    
                    
                    
                    
                    
                
            
        
    
        
        
            
        
    
        
        
            
            
            
            
            
            
            
            
            
            
                
                    
                    
                    
                    
                    /user/login=anon
                    /user/updatePwd.jsp=authc
                    /admin/*.jsp=roles[admin]
                    /user/teacher.jsp=perms["user:update"]
                    
                
            
        
    
        
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    3、ShiroUserController

    在controller包下新增ShiroUserController(登录功能)

    package com.lsy.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.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * @author 小李飞刀
     * @site www.javaxl.com
     * @company
     * @create? 2019-10-12 16:28
     */
    @Controller
    public class ShiroUserController {
    
        @RequestMapping("/login")
        public String login(HttpServletRequest req, HttpServletResponse resp){
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
            Subject subject = SecurityUtils.getSubject();
            try {
                subject.login(usernamePasswordToken);
                req.getRequestDispatcher("main.jsp").forward(req, resp);
            } catch (Exception e) {
                req.setAttribute("message", "您的用户名密码输入有误!!!");
                try {
                    req.getRequestDispatcher("login.jsp").forward(req, resp);
                } catch (ServletException e1) {
                    e1.printStackTrace();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            return null;
        }
    
        @RequestMapping("/logout")
        public String logout(HttpServletRequest req, HttpServletResponse resp){
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
            try {
                resp.sendRedirect(req.getContextPath()+"/login.jsp");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    4、导入相关jsp界面

    5、将applicationContext-shiro.xml交给spring进行管理

    6、结果

    这与shiro入门测试结果一致,变化的是shiro入门用的是死数据(ini文件),

    而这次用的是数据库数据

    ①、不填写登录

    ②、不同角色登录,查看到的功能各不相同

    张三:

    ③、权限查看

    王五登录点击用户新增显示界面

  • 相关阅读:
    Vue思考题_01v-for与v-if的优先级谁更高
    Halcon 常用通道Scale灰度元操作整理
    渗透测试--3.1.社会工程学攻击
    flat和flatMap方法
    面试学习总结
    WPF知识小结(3)
    一文搞懂MySQL索引(清晰明了)
    09 更真实的云原生:Kubeadm实际搭建多节点的Kubernetes集群
    老卫带你学---leetcode刷题(121. 买卖股票的最佳时机)
    Unity-协同程序原理
  • 原文地址:https://blog.csdn.net/web18334137065/article/details/126496496