怎么在spring中使用shiro框架-創(chuàng)新互聯(lián)

本篇文章為大家展示了怎么在spring中使用shiro框架,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

你所需要的網(wǎng)站建設服務,我們均能行業(yè)靠前的水平為你提供.標準是產(chǎn)品質(zhì)量的保證,主要從事成都網(wǎng)站制作、做網(wǎng)站、外貿(mào)營銷網(wǎng)站建設、企業(yè)網(wǎng)站建設、手機網(wǎng)站開發(fā)、網(wǎng)頁設計、成都品牌網(wǎng)站建設、網(wǎng)頁制作、做網(wǎng)站、建網(wǎng)站。創(chuàng)新互聯(lián)公司擁有實力堅強的技術研發(fā)團隊及素養(yǎng)的視覺設計專才。

shiro

Shiro是Apache下的一個開源項目,我們稱之為Apache Shiro。它是一個很易用與Java項目的的安全框架,提供了認證、授權、加密、會話管理,與spring Security 一樣都是做一個權限的安全框架,但是與Spring Security 相比,在于 Shiro 使用了比較簡單易懂易于使用的授權方式。shiro屬于輕量級框架,相對于security簡單的多,也沒有security那么復雜。更多詳細的介紹可以從它的官網(wǎng)上(http://shiro.apache.org/)基本可以了解到,她主要提供以下功能:

  (1)Authentication(認證)

 ?。?)Authorization(授權)

 ?。?)Session Management(會話管理)

 ?。?)Cryptography (加密)

首先,認證服務,也就是說通過她可以完成身份認證,讓她去判斷用戶是否為真實的會員。

其次,授權服務,說白了就是“訪問控制”服務,也就是讓她來識別用戶擁有哪些權限。再說的白一點,就是通過判斷用戶是什么角色,來賦予他哪些操作權限。

然后,還有會話管理服務, 這時一個獨立的Session管理框架,和我們熟知的Http Session 不太一樣。

最后,她還提供了Cryptography(加密)服務,封裝了很多密碼學的算法。

今天,我就不全說了,重點說下她的 會話管理功能, 其實這個也是幾乎所有的web應該都會涉及到的。

在說shiro的會話管理服務前,先回顧下之前的會話管理我們是怎么做的。

1、最初我們是直接用的web服務器的 Http Session的機制, 也就是用戶第一次進來的話,web容器會為這個請求創(chuàng)建一個session,然后把這個session存儲起來,通過將對應的sessionId,作為cookie傳給客戶端,

如果客戶端再次向這個服務器發(fā)送請求的話,會自動將這個sessionId帶過來, 然后web服務器會根據(jù)客戶端帶過來的 sessionId, 判斷其對于的session 是否還存在于內(nèi)存中(session是有過期時間的,可以在web.xml文件里面配置),如果找不到對應的session了,說明已經(jīng)過了session失效時間,這時web服務器會再次為它創(chuàng)建一個session,然后和之前一樣,將這個新的sessionId傳給客戶端。

因此,我們可以通過這種機制,在程序里管理用戶的登錄會話,比如我們在用戶第一次登錄成功后,將用戶的基本信息存儲在session里(比如:session.setAttribute("user", "userInfo") ),下次用戶再次訪問的時候,我們根據(jù)獲取當前session里的user信息

session.getAttribute("user") ),來判斷用戶是否過期,如果獲取不到,那么提示用戶重新登錄。

2、第二種方式,就是我們將存儲信息的地方轉(zhuǎn)移到第三方介質(zhì)中,比如緩存里,memecache或者Redis都可以,這種方式主要是因為分布式系統(tǒng)的出現(xiàn)而采用的。

這種情況下,就需要我們自己生成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已經(jīng)失效了,提示用戶重新登錄。

注: 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>  //這個類是需要自己實現(xiàn)的
 <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)寫一個實現(xiàn)類,繼承 AbstractSessionDAO,實現(xiàn)相應的方法。

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) {    //這就是第一次訪問的時候,創(chuàng)建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里的而用戶信息,如果獲取不到,則跳轉(zhuǎn)到登錄界面。

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());      //如果是登錄頁面的請求,則不攔截,否則會陷入死循環(huán)
 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 {

 }
}

上述內(nèi)容就是怎么在spring中使用shiro框架,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

本文標題:怎么在spring中使用shiro框架-創(chuàng)新互聯(lián)
文章來源:http://muchs.cn/article32/ipdpc.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站、面包屑導航、外貿(mào)建站、App設計、網(wǎng)站制作網(wǎng)站營銷

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設計公司