zoukankan      html  css  js  c++  java
  • 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 "没有权限访问!";
        }
    }
    
  • 相关阅读:
    10. Regular Expression Matching
    9. Palindrome Number (考虑负数的情况)
    8. String to Integer (整数的溢出)
    7. Reverse Integer (整数的溢出)
    LeetCode Minimum Size Subarray Sum
    LeetCode Course Schedule II
    Linux 文件缓存 (一)
    LeetCode Tries Prefix Tree
    Linux : lsof 命令
    LeetCode Binary Tree Right Side View
  • 原文地址:https://www.cnblogs.com/yizhixiang/p/12791300.html
Copyright © 2011-2022 走看看