首页 > 开发 > Java > 正文

springmvc集成shiro登录权限示例代码

2024-07-13 10:04:12
字体:
来源:转载
供稿:网友

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

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

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

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

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

项目依赖:

 

依赖名称  版本
spring 4.1.4.RELEASE
shiro 1.2.2
self4j 1.7.5
log4j 1.2.17

 

在web.xml里配置shiro

<filter>    <filter-name>shiroFilter</filter-name>    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>    <init-param>      <param-name>targetFilterLifecycle</param-name>      <param-value>true</param-value>    </init-param>  </filter>  <filter-mapping>    <filter-name>shiroFilter</filter-name>    <url-pattern>/*</url-pattern>  </filter-mapping>

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

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  xsi:schemaLocation="    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"  default-lazy-init="true">  <description>Shiro Configuration</description>  <!-- 安全认证过滤器 -->  <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">    <property name="securityManager" ref="securityManager" />    <property name="loginUrl" value="/sys/login" />    <property name="successUrl" value="/sys" />    <property name="filters">      <map>          <!--自定义登录验证过滤器-->        <entry key="authc" value-ref="formAuthenticationFilter" />      </map>    </property>    <property name="filterChainDefinitions">      <value>        /sys/login = authc        /sys/logout = logout        /sys/** = user      </value>    </property>  </bean>  <!-- 定义 Shiro 主要业务对象 -->  <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">    <property name="realm" ref="systemAuthorizingRealm" />    <property name="cacheManager" ref="shiroCacheManager" />  </bean>  <!-- 会话ID生成器 -->  <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>  <!-- 会话管理器,设定会话超时及保存 -->  <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">    <!-- 全局会话超时时间(单位毫秒),默认30分钟 -->    <property name="globalSessionTimeout" value="1800000" />    <property name="sessionDAO" ref="sessionDAO"/>  </bean>  <!-- 会话验证调度器,每30分钟执行一次验证 -->  <!-- <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"> -->  <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler">    <property name="interval" value="1800000"/>    <property name="sessionManager" ref="sessionManager"/>  </bean>  <!-- sessionDAO保存认证信息 -->  <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">    <property name="activeSessionsCacheName" value="shiro-activeSessionCache" />    <property name="cacheManager" ref="shiroCacheManager" />    <property name="sessionIdGenerator" ref="sessionIdGenerator"/>  </bean>  <!-- 用户授权信息Cache, 采用EhCache -->  <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">    <property name="cacheManager" ref="cacheManager" />  </bean>  <!-- Shiro生命周期处理器 -->  <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />  <!-- AOP式方法级权限检查 -->  <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">    <property name="proxyTargetClass" value="true" />  </bean>  <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">    <property name="securityManager" ref="securityManager" />  </bean></beans>

新建一个登录认证过滤器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;/** * 表单验证(包含验证码)过滤类*/@Servicepublic 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<Menu> 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<Object, AuthorizationInfo> 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<String, Object> 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<String, Object> getCacheMap() {      if (cacheMap == null) {        cacheMap = new HashMap<String, Object>();      }      return cacheMap;    }  }}

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

<%String error = (String) request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);%>       <c:set var="exp_type" value="<%=error %>"/>      <c:set var="tips" value=""></c:set>      <c:if test="${fn:contains(exp_type,'CaptchaException')}">        <c:set var="tips" value="验证码错误"></c:set>      </c:if>      <c:if test="${fn:contains(exp_type,'FailVertifyException')}">        <c:set var="tips" value="该账号审核未通过,不允许登陆!"></c:set>      </c:if>      <c:if test="${fn:contains(exp_type,'NotVertifyException')}">        <c:set var="tips" value="该账号正在审核中... 不允许登陆!"></c:set>      </c:if>      <c:if test="${fn:contains(exp_type,'UnknownAccountException')}">        <c:set var="tips" value="账号不存在!"></c:set>      </c:if>      <c:if test="${fn:contains(exp_type,'DisabledAccountException')}">        <c:set var="tips" value="账号不允许登陆!"></c:set>      </c:if>      <c:if test="${fn:contains(exp_type,'IncorrectCredentialsException')}">        <c:set var="tips" value="密码错误!"></c:set>      </c:if>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VeVb武林网。


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表