shiro是用来干嘛的?从它的官网上(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 { }
}

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

spring 整合 shiro框架的更多相关文章

  1. spring整合shiro框架

    上一篇文章已经对shiro框架做了一定的介绍,这篇文章讲述使用spring整合shiro框架,实现用户认证已经权限控制 1.搭建环境 这里不在赘述spring环境的搭建,可以简单的搭建一个ssm框架, ...

  2. spring 整合shiro框架 模拟登录控制器。

    一.导入shiro  jar包.  我在maven项目中,将常用的jar包都放在里面. <?xml version="1.0" encoding="UTF-8&qu ...

  3. Spring整合Shiro并扩展使用EL表达式

    Shiro是一个轻量级的权限控制框架,应用非常广泛.本文的重点是介绍Spring整合Shiro,并通过扩展使用Spring的EL表达式,使@RequiresRoles等支持动态的参数.对Shiro的介 ...

  4. 【Spring】Spring系列7之Spring整合MVC框架

    7.Spring整合MVC框架 7.1.web环境中使用Spring 7.2.整合MVC框架 目标:使用Spring管理MVC的Action.Controller 最佳实践参考:http://www. ...

  5. Spring整合Shiro做权限控制模块详细案例分析

    1.引入Shiro的Maven依赖 <!-- Spring 整合Shiro需要的依赖 --> <dependency> <groupId>org.apache.sh ...

  6. 【SSH框架】系列之 Spring 整合 Hibernate 框架

    1.SSH 三大框架整合原理 Spring 与 Struts2 的整合就是将 Action 对象交给 Spring 容器来负责创建. Spring 与 Hibernate 的整合就是将 Session ...

  7. Spring整合EHCache框架

    在Spring中使用缓存可以有效地避免不断地获取相同数据,重复地访问数据库,导致程序性能恶化. 在Spring中已经定义了缓存的CacheManager和Cache接口,只需要实例化便可使用. Spr ...

  8. Spring整合Struts2框架的第二种方式(Action由Spring框架来创建)(推荐大家来使用的)

    1. spring整合struts的基本操作见我的博文:https://www.cnblogs.com/wyhluckdog/p/10140588.html,这里面将spring与struts2框架整 ...

  9. Spring整合Struts2框架的第一种方式(Action由Struts2框架来创建)。在我的上一篇博文中介绍的通过web工厂的方式获取servcie的方法因为太麻烦,所以开发的时候不会使用。

    1. spring整合struts的基本操作见我的上一篇博文:https://www.cnblogs.com/wyhluckdog/p/10140588.html,这里面将spring与struts2 ...

随机推荐

  1. Dynamics CRM ADFS及IFD部署后延长系统注销时间

    Dynamics CRM 部署IFD后,一段时间后登陆状态会失效,系统会提示让你重新登陆,可以通过延长失效时间来规避 在 powershell中执行如下指令 Set-ADFSRelyingPartyT ...

  2. JAVA之旅(四)——面向对象思想,成员/局部变量,匿名对象,封装 , private,构造方法,构造代码块

    JAVA之旅(四)--面向对象思想,成员/局部变量,匿名对象,封装 , private,构造方法,构造代码块 加油吧,节奏得快点了 1.概述 上篇幅也是讲了这点,这篇幅就着重的讲一下思想和案例 就拿买 ...

  3. 《java入门第一季》之类(String类常见方法小叙)

    String类下面的构造方法和一些常见的方法: /* * 字符串:就是由多个字符组成的一串数据.也可以看成是一个字符数组. * 通过查看API,可以知道 * A:字符串字面值"abc&quo ...

  4. STL的容器算法迭代器的设计理念

    1) STL的容器通过类模板技术,实现数据类型和容器模型的分离. 2) STL的迭代器技术实现了遍历容器的统一方法:也为STL的算法提供了统一性. 3) STL的函数对象实现了自定义数据类型的算法运算 ...

  5. 《java入门第一季》之面向对象(匿名对象)

    /* 匿名对象:就是没有名字的对象. 匿名对象的应用场景: A:调用方法,仅仅只调用一次的时候. 注意:调用多次的时候,不适合. 匿名对象调用完毕就是垃圾.可以被垃圾回收器回收,释放了系统资源. B: ...

  6. 使用swift语言进行IOS应用开发

    在Swift中能够直接使用Objective-C语言提供的api (包括系统框架与自己的定制代码),也能够在Objective-C中使用Swift提供的类和api ,还能够在一个工程中同时混合使用Sw ...

  7. EBS form 之间跳转实现(form 关闭)

    实现 form CUXOMWB 使用 app_navigate.execute 打开 form CUXOEXPRAVA :然后 FROM CUXOEXPRAVA 上点击按钮 跳回from CUXOMW ...

  8. obj-c编程15[Cocoa实例01]:一个会发声的随机数生成器

    哇!终于到了obj-c编程系列的第15篇喽,一路走过来满不容易的哦!(怎么个意思,这才哪到哪啊!),为了能够更好的练习obj-c在Cocoa框架上的编程,接下来会以N篇Cocoa实例的博文来巩固和记忆 ...

  9. OS X10.10下HomeBrew的安装提示

    apple@kissAir: c_src$ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/m ...

  10. VueJs(5)---V-bind指令

    V-bind指令 一.概述 v-bind  主要用于属性绑定,比方你的class属性,style属性,value属性,href属性等等,只要是属性,就可以用v-bind指令进行绑定. 示例: < ...