• Shiro+Mybatis实现登录认证、授权功能


    Shiro+Mybatis实现登录认证、授权功能

    一、实现登录认证功能

    • 1、流程:

      • 跟据用户提交表单的账号,经Mybatis框架在数据库中查出User对象:
        • 如果User为空,则会抛出异常:UnknownAccountException,没有此账户名。
        • 如果不为空,则比对表单中的密码和User对象的密码是否相同(shiro框架自动完成,有加密),密码不相同则会抛出异常:IncorrectCredentialsException,密码错误;密码相同,则登陆成功。
    • 2、详细流程:

      • 1)代码结构如图:

        avatar

      • 2)RouterController类接收表单的请求后,将用户提交的表单数据封装成令牌,并执行方法 subjec.login(token)(用令牌登陆),下面是RouterController的部分代码

        @RequestMapping("/login")
            public String login(String usr, String pwd, Model model){
        
                //获取当前用户
                Subject subject = SecurityUtils.getSubject();
        
                //封装用户的登陆数据,生成令牌
                UsernamePasswordToken token = new UsernamePasswordToken(usr,pwd);
        
                //用令牌登陆,如果没有异常则登陆成功
                try{
                    subject.login(token);
                    //无异常则登陆成功
                    return "index";
                }catch(UnknownAccountException e){
                    model.addAttribute("msg","用户名错误");
                    return "login";
                }catch(IncorrectCredentialsException e){
                    model.addAttribute("msg","密码错误");
                    return "login";
                }
            }
        
      • 3)subjec.login(token)会调用UserRealm的认证方法doGetAuthenticationInfo(AuthenticationToken aToken)(UserRealm中有两个方法,一个授权,一个认证),下面是UserRealm的部分代码(认证方法):

        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        
            //先取令牌
            UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        
            //根据令牌信息从数据库中取出用户
            User user = userService.getUserByEmail(token.getUsername());
            if(user==null){
                return null;    //返回null,则抛出无用户名的异常
            }
        
            //验证密码,Shiro自动验证,只需要把数据库的密码传过去就好了
            return new SimpleAuthenticationInfo(user,user.getPassword(),"");
        }
        

    二、实现授权功能

    • 1、给请求设置权限,下面是ShiroConfig三病(Bean)的第一个病(Bean)ShiroFilterFactoryBean,主要负责给各种请求设置各种权限,只有拥有权限的用户才可访问请求

      @Bean	//此注解意思就是在程序开始运行前,会自动给spring托管
      public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
          ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
          //关联securityManager
          bean.setSecurityManager(securityManager);
      
          //给请求设置权限
          Map<String,String> filter = new LinkedHashMap<>();
          filter.put("/user/information","perms[user:gr]"); //有权限"user:gr"才可访问
          filter.put("/user/recommend","perms[user:tj]"); //有权限"user:tj"才可访问
          filter.put("/","anon"); //anon 谁都可以访问
      
      
      
      	//把filter加载给bean
          bean.setFilterChainDefinitionMap(filter);
      
          //当没有登陆时,跳转到此登陆界面
          bean.setLoginUrl("/tologin");
      
          //当没有权限时,跳转到此登陆界面
          bean.setUnauthorizedUrl("/noautho");
      
          return bean;
      }
      
    • 2、根据用户对象的perm(数据库中代表权限的字段)赋予当前用户权限,下面是UserRealm类中的授权方法:doGetAuthorizationInfo(PrincipalCollection principalCollection)

      //授权
      @Override
      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
          SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
      
          //拿到当前登陆的这个对象,根据这个对象的perm属性给其授权
          Subject subject = SecurityUtils.getSubject();
          User currentUser = (User)subject.getPrincipal();
      
          //授权
          info.addStringPermission(currentUser.getPerm());
      
          return info;
      }
      

    三、涉及到的主要代码

    ShiroConfig.java

    • 有三病(Bean),分别代表Shiro三核心,Bean1负责给请求设置权限
    package com.config;
    
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    @Configuration
    public class ShiroConfig{
        //shriofilterbean
        @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //关联securityManager
            bean.setSecurityManager(securityManager);
    
            //给请求设置权限
            Map<String,String> filter = new LinkedHashMap<>();
            filter.put("/user/information","perms[user:gr]");
            filter.put("/user/recommend","perms[user:tj]");
            filter.put("/","anon");
            
            bean.setFilterChainDefinitionMap(filter);
    
            //当没有登陆时,跳转到此登陆界面
            bean.setLoginUrl("/tologin");
    
            //当没有权限时,跳转到此登陆界面
            bean.setUnauthorizedUrl("/noautho");
    
            return bean;
        }
    
        //securityManager
        @Bean
        public DefaultWebSecurityManager securityManager(@Qualifier("realm") UserRealm realm){
            System.out.println("@securityManager");
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //关联realm
            securityManager.setRealm(realm);
            return securityManager;
        }
    
        //realm
        @Bean
        public UserRealm realm(){
            System.out.println("@realm");
            return new UserRealm();
        }
    
    }
    

    UserRealm.java

    • 两方法,一给用户授权,一给登陆认证
    package com.config;
    
    import com.pojo.User;
    import com.service.UserService;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    
    //自定义的realm
    public class UserRealm extends AuthorizingRealm {
        @Autowired
        private UserService userService;
    
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("@授权");
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    
            //拿到当前登陆的这个对象,根据这个对象的perm属性给其授权
            Subject subject = SecurityUtils.getSubject();
            User currentUser = (User)subject.getPrincipal();
    
            //授权
            info.addStringPermission(currentUser.getPerm());
    
            return info;
        }
    
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    
            //先取令牌
            UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
    
            //根据令牌信息从数据库中取出用户
            User user = userService.getUserByEmail(token.getUsername());
            if(user==null){
                return null;    //返回null,则抛出无用户名的异常
            }
    
            //验证密码,Shiro自动验证,只需要把数据库的密码传过去就好了
            return new SimpleAuthenticationInfo(user,user.getPassword(),"");
        }
    }
    
    

    RouterController.java

    • 负责接收请求,所有的请求接口都在这
    package com.controller;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.subject.Subject;
    import org.omg.CosNaming.NamingContextExtPackage.StringNameHelper;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    public class RouterController {
        @RequestMapping({"/","/index"})
        public String toWelcome(){
            return "index";
        }
    
        @RequestMapping("/user/information")
        public String toInformation(){
            return "user/information";
        }
    
        @RequestMapping("/user/recommend")
        public String toRecommend(){
            return "user/recommend";
        }
    
        @RequestMapping("/tologin")
        public String toLogin(){
            return "login";
        }
    
        @RequestMapping("/login")
        public String login(String usr, String pwd, Model model){
    
            //获取当前用户
            Subject subject = SecurityUtils.getSubject();
    
            //封装用户的登陆数据,生成令牌
            UsernamePasswordToken token = new UsernamePasswordToken(usr,pwd);
    
            //用令牌登陆,如果没有异常则登陆成功
            try{
                subject.login(token);
                //无异常则登陆成功
                return "index";
            }catch(UnknownAccountException e){
                model.addAttribute("msg","用户名错误");
                return "login";
            }catch(IncorrectCredentialsException e){
                model.addAttribute("msg","密码错误");
                return "login";
            }
        }
    
        @RequestMapping("/noautho")
        @ResponseBody
        public String toNoautho(){
            return "没有权限访问!";
        }
    }
    
  • 相关阅读:
    HTTP协议一次上传多个文件的方法
    PHP中include和require的区别
    jenkins持续集成工具
    vue加强(第二天)
    VUE(第一天)
    mybatis的SQL映射(加强)
    easyPOI的上传和下载(导入和导出功能)
    shiro登录授权框架
    SpringDataJPA(ORM对象关系映射框架)
    SpringSpringMVCJPA集成
  • 原文地址:https://www.cnblogs.com/yizhixiang/p/12791300.html
Copyright © 2020-2023  润新知