springmvc利用shiro实现登录权限功能

这篇文章运用简单易懂的例子给大家介绍springmvc利用shiro实现登录权限功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

创新互联公司欢迎咨询:028-86922220,为您提供成都网站建设网页设计及定制高端网站建设服务,创新互联公司网页制作领域十余年,包括成都混凝土泵车等多个行业拥有丰富的营销推广经验,选择创新互联公司,为网站锦上添花。

一般的登录流程会有:用户名不存在,密码错误,验证码错误等..

在集成shiro后,应用程序的外部访问权限以及访问控制交给了shiro来管理。

shiro提供了两个主要功能:认证(Authentication)和授权(Authorization);认证的作用是证明自身可以访问,一般是用户名加密码,授权的作用是谁可以访问哪些资源,通过开发者自己的用户角色权限系统来控制。

shiro的会话管理和缓存管理不在本文范围内。

下面通过登录失败的处理流程来介绍springmvc与shiro的集成。

项目依赖:

依赖名称 版本
spring4.1.4.RELEASE
shiro1.2.2
self4j1.7.5
log4j1.2.17

在web.xml里配置shiro


    shiroFilter
    org.springframework.web.filter.DelegatingFilterProxy
    
      targetFilterLifecycle
      true
    
  
  
    shiroFilter
    /*
  

新建一个spring-context-shiro.xml配置shiro相关信息,使用spring加载

<?xml version="1.0" encoding="UTF-8"?>


  Shiro Configuration
  
  
    
    
    
    
      
          
        
      
    
    
      
        /sys/login = authc
        /sys/logout = logout
        /sys/** = user
      
    
  

  
  
    
    
  
  
  
  
  
    
    
    
  
  
  
  
    
    
  
  
  
    
    
    
  
  
  
    
  
  
  

  
  
    
  
  
    
  

新建一个登录认证过滤器FormAuthenticationFilter.java

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.stereotype.Service;

/**
 * 表单验证(包含验证码)过滤类*/
@Service
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {
  public static final String DEFAULT_CAPTCHA_PARAM = "validateCode";

  private String captchaParam = DEFAULT_CAPTCHA_PARAM;

  public String getCaptchaParam() {
    return captchaParam;
  }

  protected String getCaptcha(ServletRequest request) {
    return WebUtils.getCleanParam(request, getCaptchaParam());
  }

  protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
    String username = getUsername(request);
    String password = getPassword(request);
    String locale = request.getParameter("locale");
    
    if (password == null) {
      password = "";
    }
    boolean rememberMe = isRememberMe(request);
    String host = getHost(request);
    String captcha = getCaptcha(request);
    return new UsernamePasswordToken(username, password.toCharArray(),locale, rememberMe, host, captcha);
  }
}

新建令牌类UsernamePasswordToken.java

package com.chunhui.webservice.modules.sys.security;

/**
 * 用户和密码(包含验证码)令牌类*/
public class UsernamePasswordToken extends org.apache.shiro.authc.UsernamePasswordToken {
  private static final long serialVersionUID = 1L;
  private String captcha;
  private String locale;
  
  public String getCaptcha() {
    return captcha;
  }

  public void setCaptcha(String captcha) {
    this.captcha = captcha;
  }

  public String getLocale() {
    return locale;
  }

  public void setLocale(String locale) {
    this.locale = locale;
  }

  public UsernamePasswordToken() {
    super();
  }

  public UsernamePasswordToken(String username, char[] password, boolean rememberMe, String host, String captcha) {
    super(username, password, rememberMe, host);
    this.captcha = captcha;
  }
  public UsernamePasswordToken(String username, char[] password, String locale,boolean rememberMe, String host, String captcha) {
    super(username, password, rememberMe, host);
    this.captcha = captcha;
    this.locale = locale;
  }
}

最后一个是认证实现类SystemAuthorizationRealm:

package com.chunhui.webservice.modules.sys.security;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;

import com.chunhui.webservice.common.utils.EmployeeType;
import com.chunhui.webservice.common.utils.VertifyStatus;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import com.chunhui.webservice.common.servlet.ValidateCodeServlet;
import com.chunhui.webservice.common.utils.SpringContextHolder;
import com.chunhui.webservice.modules.sys.entity.Employee;
import com.chunhui.webservice.modules.sys.entity.Menu;
import com.chunhui.webservice.modules.sys.service.SystemService;
import com.chunhui.webservice.modules.sys.utils.SystemUtils;
import com.chunhui.webservice.modules.sys.web.LoginController;

/**
 * 系统安全认证实现类*/
@Service
@DependsOn({ "employeeDao", "roleDao", "menuDao" })
public class SystemAuthorizingRealm extends AuthorizingRealm {
  private SystemService systemService;

  /**
   * 认证回调函数, 登录时调用
   */
  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
    UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
// 判断验证码
    Session session = SecurityUtils.getSubject().getSession();
    // 设置独立的session会话超时时间 session.setTimeout(60000);
    String code = (String) session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);
    if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)) {
      throw new CaptchaException("验证码错误!");
    }
    
     //如果帐号不存在,输出
    //throw new UnknownAccountException();
    
    //如果帐号被禁用,输出      
    //throw new DisabledAccountException();
      
    //保存登录时选择的语言
    SecurityUtils.getSubject().getSession().setAttribute("locale", token.getLocale());
    try{
      SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(new Principal(employee), employee.getPassword(), getName());
      return info;
    }catch (Throwable t){
      t.printStackTrace();
      throw new AuthenticationException();
    }
  }/**
   * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用
   */
  @Override
  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    Principal principal = (Principal) getAvailablePrincipal(principals);
    Employee employee = getSystemService().getEmployeeByName(principal.getUsername());
    if (employee != null) {
      SystemUtils.putCache("employee", employee);
      SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
      List list = SystemUtils.getMenuList();
      for (Menu menu : list) {
        if (StringUtils.isNotBlank(menu.getPermission())) {
          // 添加基于Permission的权限信息
          for (String permission : StringUtils.split(menu.getPermission(), ",")) {
            info.addStringPermission(permission);
          }
        }
      }
      // 更新登录IP和时间
      getSystemService().updateEmployeeLoginInfo(employee.getId());
      return info;
    } else {
      return null;
    }
  }

  /**
   * 清空用户关联权限认证,待下次使用时重新加载
   */
  public void clearCachedAuthorizationInfo(String principal) {
    SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
    clearCachedAuthorizationInfo(principals);
  }

  /**
   * 清空所有关联认证
   */
  public void clearAllCachedAuthorizationInfo() {
    Cache cache = getAuthorizationCache();
    if (cache != null) {
      for (Object key : cache.keys()) {
        cache.remove(key);
      }
    }
  }

  /**
   * 获取系统业务对象
   */
  public SystemService getSystemService() {
    if (systemService == null) {
      systemService = SpringContextHolder.getBean(SystemService.class);
    }
    return systemService;
  }

  /**
   * 授权用户信息
   */
  public static class Principal implements Serializable {
    private static final long serialVersionUID = 1L;

    private String id;
    private String username;
    private String realname;
    private Map cacheMap;

    public Principal(Employee employee) {
      this.id = employee.getId();
      this.username = employee.getUsername();
      this.realname = employee.getRealname();
    }

    public String getId() {
      return id;
    }

    public String getUsername() {
      return username;
    }

    public String getRealname() {
      return realname;
    }

    public Map getCacheMap() {
      if (cacheMap == null) {
        cacheMap = new HashMap();
      }
      return cacheMap;
    }
  }
}

那么在JSP页面,可以通过获取登录异常具体的异常类型来在页面显示错误原因

<%String error = (String) request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);%>
       
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      

关于springmvc利用shiro实现登录权限功能就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。


文章标题:springmvc利用shiro实现登录权限功能
文章路径:http://myzitong.com/article/pgjgjh.html