spring整合shiro框架的实现步骤记录

shiro

Shiro是Apache下的一个开源项目,我们称之为Apache Shiro。它是一个很易用与Java项目的的安全框架,提供了认证、授权、加密、会话管理,与spring Security 一样都是做一个权限的安全框架,但是与Spring Security 相比,在于 Shiro 使用了比较简单易懂易于使用的授权方式。shiro属于轻量级框架,相对于security简单的多,也没有security那么复杂。更多详细的介绍可以从它的官网上(http://shiro.apache.org/)基本可以了解到,她主要提供以下功能:

  (1)Authentication(认证)

  (2)Authorization(授权)

  (3)Session Management(会话管理)

  (4)Cryptography (加密)

首先,认证服务,也就是说通过她可以完成身份认证,让她去判断用户是否为真实的会员。

其次,授权服务,说白了就是“访问控制”服务,也就是让她来识别用户拥有哪些权限。再说的白一点,就是通过判断用户是什么角色,来赋予他哪些操作权限。

然后,还有会话管理服务, 这时一个独立的Session管理框架,和我们熟知的Http Session 不太一样。

最后,她还提供了Cryptography(加密)服务,封装了很多密码学的算法。

今天,我就不全说了,重点说下她的 会话管理功能, 其实这个也是几乎所有的web应该都会涉及到的。

在说shiro的会话管理服务前,先回顾下之前的会话管理我们是怎么做的。

1、最初我们是直接用的web服务器的 Http Session的机制, 也就是用户第一次进来的话,web容器会为这个请求创建一个session,然后把这个session存储起来,通过将对应的sessionId,作为cookie传给客户端,

如果客户端再次向这个服务器发送请求的话,会自动将这个sessionId带过来, 然后web服务器会根据客户端带过来的 sessionId, 判断其对于的session 是否还存在于内存中(session是有过期时间的,可以在web.xml文件里面配置),如果找不到对应的session了,说明已经过了session失效时间,这时web服务器会再次为它创建一个session,然后和之前一样,将这个新的sessionId传给客户端。

因此,我们可以通过这种机制,在程序里管理用户的登录会话,比如我们在用户第一次登录成功后,将用户的基本信息存储在session里(比如:session.setAttribute("user", "userInfo") ),下次用户再次访问的时候,我们根据获取当前session里的user信息

session.getAttribute("user") ),来判断用户是否过期,如果获取不到,那么提示用户重新登录。

2、第二种方式,就是我们将存储信息的地方转移到第三方介质中,比如缓存里,memecache或者Redis都可以,这种方式主要是因为分布式系统的出现而采用的。

这种情况下,就需要我们自己生成sessionId了,一般我们会用一个定义好的前缀(user:login:token)再加上userid,或者时间戳都可以。 然后我们会将这个sessionId作为缓存的key, 用户的信息作为value,存入缓存中,并设置失效时间:

  jedisClient.set(tokenKey, JsonUtil.toJSONString(userInfo));
  jedisClient.expire(tokenKey, TOKEN_LOSE_SECONDS);

我们还要将生成的这个tokenKey通过cookie传到客户端: CookieUtils.setCookie(request, response, "TT_TOKEN", tokenKey);

这样,我们在用户下次访问的时候(定义一个拦截器),就可以从cookie里取出对应的tokenKey,然后用这个tokenKey去到缓存里取相应的值,如果获取不到,说明这个key已经失效了,提示用户重新登录。

注: tokenKey 很重要,她是连接缓存端和客户端的枢纽。

3、最后一种就是我们shiro方式了,思路也类似,代码挺简单的,那我就直接上代码吧:

1)、新建一个 applicationContext-shiro.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
 <property name="securityManager" ref="securityManager"></property>
 <property name="loginUrl" value="/loginPage"></property>
 <property name="unauthorizedUrl" value="/pages/unauthorized.jsp"/>
 <property name="filterChainDefinitions">
 <value>
 /jcaptcha* = anon
 /logout = anon
 </value>
 </property>
 </bean>

 <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
 <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"></property>
 <property name="arguments" ref="securityManager"></property>
 </bean>
 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
 <property name="cacheManager" ref="cacheManager"></property>
 <property name="sessionManager" ref="sessionManager"></property>
 </bean>
 <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
 <property name="sessionDAO" ref="sessionDAO"></property>
 </bean>
 <bean id="sessionDAO" class="com.smart.core.shiro.MySessionDAO"></bean>  //这个类是需要自己实现的
 <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"></bean>
</beans>

2)、在web.xml 里配置相应的 filter:

<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>

3)写一个实现类,继承 AbstractSessionDAO,实现相应的方法。

package com.jdd.core.shiro;

import com.smart.core.redis.RedisManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.SerializationUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.Collection;

public class MySessionDAO extends AbstractSessionDAO {

 @Autowired
 private RedisManager redisManager;

 @Override
 public void update(Session session) throws UnknownSessionException {
 redisManager.set(SerializationUtils.serialize(session.getId().toString()), SerializationUtils.serialize(session));
 redisManager.expire(SerializationUtils.serialize(session.getId().toString()), 60);
 }

 @Override
 public void delete(Session session) {
 redisManager.del(SerializationUtils.serialize(session.getId().toString()));
 }

 @Override
 public Collection<Session> getActiveSessions() {
 return new ArrayList<Session>();
 }

 @Override
 protected Serializable doCreate(Session session) {    //这就是第一次访问的时候,创建sessionId
 Serializable sid = this.generateSessionId(session);
 assignSessionId(session, sid);
 redisManager.set(SerializationUtils.serialize(session.getId().toString()), SerializationUtils.serialize(session));
 redisManager.expire(SerializationUtils.serialize(session.getId().toString()), 60);
 return sid;
 }

 @Override
 protected Session doReadSession(Serializable serializable) {  //这个方法其实就是通过sessionId读取session,每读一次,都要重新设置失效时间
 byte[] aa = redisManager.get(SerializationUtils.serialize(serializable.toString()));
 Session session = (Session) SerializationUtils.deserialize(aa);
 redisManager.set(SerializationUtils.serialize(serializable.toString()), SerializationUtils.serialize(session));
 redisManager.expire(SerializationUtils.serialize(serializable.toString()), 60);
 return session;
 }
}

4)下一步,我就是要在登录成功之后的逻辑里,获取到shiro 的session,然后将用户信息设置进去

package com.smart.controller;
import com.smart.pojo.User;
import com.smart.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
@RequestMapping("/user")
public class UserController {

 @Autowired
 private UserService userService;
 @Autowired
 private SecurityManager sm;  //注入SecurityManager

 private Logger logger = LoggerFactory.getLogger(UserController.class);

 @RequestMapping(value = "/loginPage")
 public String loginPage(){
 return "user/userLogin";
 }

 @RequestMapping(value = "/userLogin", method = RequestMethod.POST)
 public String userLogin(@RequestParam(value="name") String name, @RequestParam(value="pwd") String pwd, Model model){

 logger.info("enter userLogin...");
 User user = userService.getUserByNameAndPassword(name, pwd);
 if(user == null){
  logger.info("user is not exist...");
  model.addAttribute("login_error", "用户名或密码错误");
  return "user/userLogin";
 }

 SecurityUtils.setSecurityManager(sm);
 Subject currentUser = SecurityUtils.getSubject();    
 currentUser.getSession().setAttribute("LOGIN_USER", user); 
 return "redirect:/employee/list";
 }
}

获取当前用户,在shiro里是主题,然后获取对应的session,并将用户信息设置进去,是不是感觉有点像Http session的操作的样子,哈哈。

5)、最后,定义一个springmvc 的拦截器,在拦截器里获取相应的session里的而用户信息,如果获取不到,则跳转到登录界面。

package com.smart.core.shiro;

import com.smart.pojo.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginInterceptor implements HandlerInterceptor {

 private Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);

 @Autowired
 private SecurityManager sm;

 @Override
 public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
 logger.info("enter LoginInterceptor...");
 HttpServletRequest request = httpServletRequest;
 HttpServletResponse response = httpServletResponse;
 logger.info("request uri===>"+request.getRequestURI());      //如果是登录页面的请求,则不拦截,否则会陷入死循环
 if(request.getRequestURI().contains("loginPage") || request.getRequestURI().contains("userLogin")){
  return true;
 }else{
  SecurityUtils.setSecurityManager(sm);
  Subject currentUser = SecurityUtils.getSubject();
  Object obj = currentUser.getSession().getAttribute("LOGIN_USER");
  if(obj==null){
  response.sendRedirect("http://localhost:8080/user/loginPage");
  return false;
  }else{
  User user = (User)obj;
  if(user==null || user.getName()==null){
   response.sendRedirect("http://localhost:8080/user/loginPage");
   return false;
  }else{
   return true;
  }
  }

 }

 }

 @Override
 public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

 }

 @Override
 public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

 }
}

到这里就基本结束了,如果你现在直接访问主页信息的话,它会自动跳到登录页面。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • SpringBoot整合Shiro实现登录认证的方法

    安全无处不在,趁着放假读了一下 Shiro 文档,并记录一下 Shiro 整合 Spring Boot 在数据库中根据角色控制访问权限 简介 Apache Shiro是一个功能强大.灵活的,开源的安全框架.它可以干净利落地处理身份验证.授权.企业会话管理和加密. 上图是 Shiro 的基本架构 Authentication(认证) 有时被称为"登录",用来证明用户是用户他们自己本人 Authorization(授权) 访问控制的过程,即确定"谁"访问"什么

  • 详解spring整合shiro权限管理与数据库设计

    之前的文章中我们完成了基础框架的搭建,现在基本上所有的后台系统都逃不过权限管理这一块,这算是一个刚需了.现在我们来集成shiro来达到颗粒化权限管理,也就是从连接菜单到页面功能按钮,都进行权限都验证,从前端按钮的显示隐藏,到后台具体功能方法的权限验证. 首先要先设计好我们的数据库,先来看一张比较粗糙的数据库设计图: 具体的数据库设计代码 /* Navicat MySQL Data Transfer Source Server : 本机 Source Server Version : 50537

  • SpringBoot整合Shiro的代码详解

    shiro是一个权限框架,具体的使用可以查看其官网 http://shiro.apache.org/  它提供了很方便的权限认证和登录的功能. 而springboot作为一个开源框架,必然提供了和shiro整合的功能!接下来就用springboot结合springmvc,mybatis,整合shiro完成对于用户登录的判定和权限的验证. 1.准备数据库表结构 这里主要涉及到五张表:用户表,角色表(用户所拥有的角色),权限表(角色所涉及到的权限),用户-角色表(用户和角色是多对多的),角色-权限表

  • spring boot整合Shiro实现单点登录的示例代码

    Shiro是什么 Shiro是一个Java平台的开源权限框架,用于认证和访问授权.具体来说,满足对如下元素的支持: 用户,角色,权限(仅仅是操作权限,数据权限必须与业务需求紧密结合),资源(url). 用户分配角色,角色定义权限. 访问授权时支持角色或者权限,并且支持多级的权限定义. Q:对组的支持? A:shiro默认不支持对组设置权限. Q:是否可以满足对组进行角色分配的需求? A:扩展Realm,可以支持对组进行分配角色,其实就是给该组下的所有用户分配权限. Q:对数据权限的支持? 在业务

  • Spring MVC整合Shiro权限控制的方法

    Apache Shiro 是一个功能强大且灵活的开放源代码安全框架,可以细粒度地处理认证 (Authentication),授权 (Authorization),会话 (Session) 管理和加密 (cryptography) 等企业级应用中常见的安全控制流程. Apache Shiro 的首要目标是易于使用和理解. 有时候安全性的流程控制会非常复杂,对开发人员来说是件很头疼的事情,但并不一定如此. 框架就应该尽可能地掩盖复杂性,并公开一个简洁而直观的 API,从而简化开发人员的工作,确保其应

  • Apache shiro的简单介绍与使用教程(与spring整合使用)

    apache shiro框架简介 Apache Shiro是一个强大而灵活的开源安全框架,它能够干净利落地处理身份认证,授权,企业会话管理和加密.现在,使用Apache Shiro的人越来越多,因为它相当简单,相比比Spring Security,Shiro可能没有Spring Security那么多强大的功能,但是在实际工作时可能并不需要那么复杂的东西,所以使用简单的Shiro就足够了. 以下是你可以用 Apache Shiro所做的事情: Shiro的4大核心部分--身份验证,授权,会话管理

  • spring boot整合redis实现shiro的分布式session共享的方法

    我们知道,shiro是通过SessionManager来管理Session的,而对于Session的操作则是通过SessionDao来实现的,默认的情况下,shiro实现了两种SessionDao,分别为CachingSessionDAO和MemorySessionDAO,当我们使用EhCache缓存时,则是使用的CachingSessionDAO,不适用缓存的情况下,就会选择基于内存的SessionDao.所以,如果我们想实现基于Redis的分布式Session共享,重点在于重写Session

  • Spring 整合Shiro 并扩展使用EL表达式的实例详解

    Shiro是一个轻量级的权限控制框架,应用非常广泛.本文的重点是介绍Spring整合Shiro,并通过扩展使用Spring的EL表达式,使@RequiresRoles等支持动态的参数.对Shiro的介绍则不在本文的讨论范围之内,读者如果有对shiro不是很了解的,可以通过其官方网站了解相应的信息.infoq上也有一篇文章对shiro介绍比较全面的,也是官方推荐的,其地址是https://www.infoq.com/articles/apache-shiro. Shiro整合Spring 首先需要

  • spring整合shiro框架的实现步骤记录

    shiro Shiro是Apache下的一个开源项目,我们称之为Apache Shiro.它是一个很易用与Java项目的的安全框架,提供了认证.授权.加密.会话管理,与spring Security 一样都是做一个权限的安全框架,但是与Spring Security 相比,在于 Shiro 使用了比较简单易懂易于使用的授权方式.shiro属于轻量级框架,相对于security简单的多,也没有security那么复杂.更多详细的介绍可以从它的官网上(http://shiro.apache.org/

  • Spring整合Dubbo框架过程及原理解析

    这篇文章主要介绍了Spring整合Dubbo框架过程及原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Dubbo作为一个RPC框架,其最核心的功能就是要实现跨网络的远程调用.演示过程创建两个小工程,一个作为服务的提供者,一个作为服务的消费者.通过Dubbo来实现服务消费者远程调用服务提供者的方法. dubbo 的使用需要一个注册中心,这里以Zookeeper为例来演示 1.Dubbo架构 Dubbo架构图(Dubbo官方提供)如下: 节

  • spring整合cxf框架实例

    CXF是webService的框架,能够和spring无缝整合 ##服务端编写 1.创建动态web项目 2.导入cxf和spring相关jar包(CXF核心包:cxf-2.4.2.jar) 3.在web.xml中配置CXF框架的核心Servlet <servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</s

  • spring整合Quartz框架过程详解

    这篇文章主要介绍了spring整合Quartz框架过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.Quartz框架简介 Quartz是一个完全由Java编写的开源任务调度的框架,通过触发器设置作业定时运行规则,控制作业的运行时间.其中quartz集群通过故障切换和负载平衡的功能,能给调度器带来高可用性和伸缩性.主要用来执行定时任务,如:定时发送信息.定时生成报表等等. Quartz框架的主要特点: · 强大的调度功能,例如丰富多样的

  • ssm整合之Spring整合MyBatis框架配置事务的详细教程

    ssm整合之Spring整合MyBatis框架配置事务 1.在applicationContext.xml修改代码如下: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance

  • SpringBoot整合Shiro框架,实现用户权限管理

    一.Shiro简介 核心角色 1)Subject:认证主体 代表当前系统的使用者,就是用户,在Shiro的认证中,认证主体通常就是userName和passWord,或者其他用户相关的唯一标识. 2)SecurityManager:安全管理器 Shiro架构中最核心的组件,通过它可以协调其他组件完成用户认证和授权.实际上,SecurityManager就是Shiro框架的控制器. 3)Realm:域对象 定义了访问数据的方式,用来连接不同的数据源,如:关系数据库,配置文件等等. 核心理念 Shi

  • 详解Java springboot 整合Shiro框架

    目录 Shiro介绍 Springboot整合Shiro Shiro整合Thymeleaf 总结 Shiro介绍 Shiro是一款安全框架,主要的三个类Subject.SecurityManager.Realm Subject:表示当前用户 SecurityManager:安全管理器,即所有与安全有关的操作都会与SecurityManager交互:且其管理着所有Subject:可以看出它是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMVC中DispatcherSe

  • SpringBoot2.0整合Shiro框架实现用户权限管理的示例

    GitHub源码地址:知了一笑 https://github.com/cicadasmile/middle-ware-parent 一.Shiro简介 1.基础概念 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.作为一款安全框架Shiro的设计相当巧妙.Shiro的应用不依赖任何容器,它不仅可以在JavaEE下使用,还可以应用在JavaSE环境中. 2.核心角色 1)Subject:认证主体 代表当前系统的使用者,就是用户,在Shiro的认证中,

随机推荐