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

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

在集成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;

/**
 * 表单验证(包含验证码)过滤类*/
@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<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>

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

(0)

相关推荐

  • Eclipse 使用Maven构建SpringMVC项目

    首先Eclipse需要安装Maven的插件,地址:http://m2eclipse.sonatype.org/sites/m2e. 用MyEclipse安装Maven插件,建出的Maven项目有些问题.一是,发布tomcat的时候resources总是不会被发布到tomcat下:二是,把WEB-INF下的classes改到target下的classes,但是不知道为什么MyEclipse要么仍然在WEB-INF下生成class.要么真不在WEB-INF生成classes了但是发布tomcat的时

  • springmvc+maven搭建web项目

    本文实例为大家分享了springmvc maven搭建web项目的具体步骤,供大家参考,具体内容如下 1.创建一个maven project 为spring1 2.进行项目的配置:默认的java 1.5 在properties中选择project facts项目进行配置,反选web之后修改java环境为1.8.修改之后如下图: 3. 配置好的工作目录如下: 4 修改pom.xml文件 增加两个jar包:servlet和spring webmvc pom.xml如下: <!DOCTYPE web-

  • springboot+maven快速构建项目的示例代码

    最近公司运用springboot构建项目,确实比ssh搭建要快很多. 1.首先要下载maven,用maven管理项目很方便,下载完maven配置好环境,maven我就不细说了. 2.创建一个maven项目,pom.xml文件里面写这些: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:sche

  • Maven 搭建SpringMVC+Hibernate项目详解

    前言 今天复习一下SpringMVC+Hibernate的搭建,本来想着将Spring-Security权限控制框架也映入其中的,但是发现内容太多了,Spring-Security的就留在下一篇吧,这篇主要搭建SpringMVC4.1.4和Hibernate4.3.8,之前也打了好多SpringMVC的,这部分已经非常的熟悉了,毕竟业开发过一年多SpringMVC的,这次持久层采用Hibernate,数据源采用c3p0,数据库暂采用MySQL,主要是想复习一下Hibernate.搭建Spring

  • springmvc+shiro+maven 实现登录认证与权限授权管理

    Shiro 是Shiro 是一个 Apache 下的一开源项目项目,旨在简化身份验证和授权. 1:shiro的配置,通过maven加入shiro相关jar包 <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.1</version> <

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

    一般的登录流程会有:用户名不存在,密码错误,验证码错误等.. 在集成shiro后,应用程序的外部访问权限以及访问控制交给了shiro来管理. shiro提供了两个主要功能:认证(Authentication)和授权(Authorization);认证的作用是证明自身可以访问,一般是用户名加密码,授权的作用是谁可以访问哪些资源,通过开发者自己的用户角色权限系统来控制. shiro的会话管理和缓存管理不在本文范围内. 下面通过登录失败的处理流程来介绍springmvc与shiro的集成. 项目依赖:

  • springmvc集成shiro登录失败处理操作

    一般的登录流程会有:用户名不存在,密码错误,验证码错误等.. 在集成shiro后,应用程序的外部访问权限以及访问控制交给了shiro来管理. shiro提供了两个主要功能:认证(Authentication)和授权(Authorization);认证的作用是证明自身可以访问,一般是用户名加密码,授权的作用是谁可以访问哪些资源,通过开发者自己的用户角色权限系统来控制. shiro的会话管理和缓存管理不在本文范围内. 下面通过登录失败的处理流程来介绍springmvc与shiro的集成. 依赖项目

  • springboot集成CAS实现单点登录的示例代码

    最近新参与的项目用到了cas单点登录,我还不会,这怎么能容忍!空了学习并搭建了一个spring-boot 集成CAS 的demo.实现了单点登录与登出. 单点登录英文全称是:Single Sign On,简称SSO. 含义:在多个相互信任的系统中,只要登录一个系统其他系统均可访问. CAS 是一种使用广泛的单点登录实现,分为客户端CAS Client和服务端 CAS Service,客户端就是我们的系统,服务端是认证中心,由CAS提供,我们需要稍作修改,启动起来就可以用.~~~~ 效果演示 ht

  • SpringBoot集成Auth0 JWT的示例代码

    目录 前言 session认证与Token认证 session认证 Token认证 JWT简介 JWT定义 JWT的类库 具体实现 JWT配置 JWT工具类 测试接口 前言 说说JWT,先说下互联网服务常见的两种用户认证方式: session认证与Token认证 session认证 传统的Session认证的大体流程可以表示为用户提供用户名和密码登录后由服务器存储一份用户登录信息并传递给浏览器保存为Cookie,并在下次请求中根据Cookie来识别用户,但这种方式缺陷明显: Session都是保

  • 使用GitLab+Jenkins实现持续集成CI环境的示例代码

    目录 一.持续集成简介 1.GitLab 简介 2.Jenkins 简介 3.GitLab 和 GitHub 的区别 4.持续集成系统的工作流程 二.使用 GitLab + Jenkins 实现持续集成(CI)环境 1.安装 Gitlab 1)登录 Gitlab 2)配置邮件报警 3)创建群组 4)创建项目 5)配置免密克隆 2.安装 Jenkins 1)登录 Jenkins,并安装相关插件 2)配置 Jenkins 实现 GitLab 更新代码 3)在 Jenkins 上创建项目 4)将代码发

  • springboot 集成支付宝支付的示例代码

    最简单的springboot集成支付宝 1 注册沙箱 沙箱是一个模拟环境登录,百度蚂蚁金服开放平台,支付宝扫码登录如下 然后沙箱需要注册一下,非常之简单,注册好以后进入到如下页面,选沙箱工具,然后下载一个生成密钥的工具.然后解压按照里面的readme生成公私密钥, 选择沙箱应用 上传公钥即可..沙箱到这里就基本完成了,里面还有沙箱版本的的android app可以下载下来. java 程序 1 新建一个springboot项目 因为我们创建的是一个web工程,所以,仅仅演示支付宝的demo,只需

  • spring cloud oauth2 实现用户认证登录的示例代码

    需求 在微服务架构中,我们有很多业务模块,每个模块都需要有用户认证,权限校验.有时候也会接入来自第三方厂商的应用.要求是只登录一次,即可在各个服务的授权范围内进行操作.看到这个需求,立马就想到了这不就是单点登录吗?于是基于这样的需求,作者使用spring-cloud-oauth2去简单的实现了下用户认证和单点登录. 相关介绍 OAuth2 OAuth2是一个关于授权的网络标准,他定制了设计思路和执行流程.OAuth2一共有四种授权模式:授权码模式(authorization code).简化模式

  • SpringBoot整合Keycloak实现单点登录的示例代码

    目录 1. 搭建Keycloak服务器 2. 配置权限 2.1. 登陆 2.2. 创建Realm 2.3. 创建用户 2.4. 创建客户端 2.5. 创建角色 2.6. 配置用户角色关系 2.7. 配置客户端和角色关系 3. 整合SpringBoot 3.1. 引入核心依赖 3.2. 编写Controller 3.3. 编写application.yml 4. 验证 Keycloak是一个开源的身份和权限访问管理工具,轻松为应用程序和安全服务添加身份验证,无需处理储存用户或者验证用户,其提供用户

  • python实现网站微信登录的示例代码

    最近微信登录开放公测,为了方便微信用户使用,我们的产品也决定加上微信登录功能,然后就有了这篇笔记. 根据需求选择相应的登录方式 python实现网站微信登录的示例代码 微信现在提供两种登录接入方式 移动应用微信登录 网站应用微信登录 这里我们使用的是网站应用微信登录 按照 官方流程 1 注册并通过开放平台开发者资质认证 注册微信开放平台帐号后,在帐号中心中填写开发者资质认证申请,并等待认证通过. 2 创建网站应用 通过填写网站应用名称.简介和图标,以及各平台下载地址等资料,创建网站应用 3 接入

  • SpringBoot集成slf4j+log4j2的示例代码

    本文介绍了SpringBoot集成slf4j+log4j2的示例代码,分享给大家,具体如下: Maven依赖 <!--增加log4j2依赖↓--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <dependency&g

随机推荐