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 "没有权限访问!";
    }
}
原文地址:https://www.cnblogs.com/yizhixiang/p/12791300.html