1. 程式人生 > 程式設計 >shiro整合springboot前後端分離

shiro整合springboot前後端分離

本文例項為大家分享了shiro整合springboot前後端分離的具體程式碼,供大家參考,具體內容如下

1、shiro整合springboot的配置

package com.hisi.config;
 
import java.util.LinkedHashMap;
import java.util.Map;
 
import javax.servlet.Filter;
 
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
 
import com.hisi.shiro.LoginAuthorizationFilter;
import com.hisi.shiro.RestFilter;
import com.hisi.shiro.UserRealm;
 
/**
 * shiro許可權管理的配置
 * @author xuguoqin
 * @date 2018年5月4日
 * @version 1.0
 */
@Configuration
public class ShiroConfig {
 
 /**
 * 安全管理器
 * @param realm
 * @return
 */
 @Bean
 public DefaultWebSecurityManager securityManager(){
 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
 securityManager.setRealm(userRealm());
 securityManager.setSessionManager(sessionManager());
 return securityManager;
 }
 
 /**
 * Realm配置
 * @return
 */
 @Bean
 public UserRealm userRealm(){
 return new UserRealm();
 }
 
 /**
 * SessionDAO配置
 * @return
 */
 @Bean
 public SessionDAO sessionDAO(){
 return new MemorySessionDAO();
 }
 
 /**
 * sessionManager配置
 * @param sessionDAO
 * @return
 */
 @Bean
 public DefaultWebSessionManager sessionManager(){
 DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
 sessionManager.setSessionDAO(sessionDAO());
 return sessionManager;
 }
 
 /**
 * shiroFilter配置
 * @param securityManager
 * @return
 */
 @Bean
 public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
 
 ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
 shiroFilter.setSecurityManager(securityManager());
 Map<String,Filter> filters = new LinkedHashMap<String,Filter>();
 filters.put("token",new LoginAuthorizationFilter());
 filters.put("corsFilter",new RestFilter());
 shiroFilter.setFilters(filters);
 Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
 filterChainDefinitionMap.put("/user/login","corsFilter,anon");
 filterChainDefinitionMap.put("/user/logout",anon");
 filterChainDefinitionMap.put("/user/**",token");
 shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);
 return shiroFilter;
 }
 
 /**
   * 保證實現了Shiro內部lifecycle函式的bean執行
   */
  @Bean
  public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
    return new LifecycleBeanPostProcessor();
  }
 
  /**
   * 啟用shrio授權註解攔截方式,AOP式方法級許可權檢查
   */
  @Bean
  @DependsOn(value = "lifecycleBeanPostProcessor") //依賴其他bean的初始化
  public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    return new DefaultAdvisorAutoProxyCreator();
  }
 
 /**
 * 加入註解的使用,不加入這個註解不生效 使用shiro框架提供的切面類,用於建立代理物件 
 * @param securityManager
 * @return
 */
  @Bean
  public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
    AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
    return authorizationAttributeSourceAdvisor;
  }
  
  
}

2、這裡配置的兩個過濾器RestFilter和LoginAuthorizationFilter,RestFilter是用於解決前後端分離時的跨域問題,服務端在響應頭設定可以接受的請求引數

package com.hisi.shiro;
 
import java.io.IOException;
import java.util.Optional;
 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * 前後端分離RESTful介面過濾器
 * 
 * @author xuguoqin
 *
 */
public class RestFilter implements Filter {
 
 @Override
 public void init(FilterConfig filterConfig) throws ServletException {
 
 }
 
 @Override
 public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
  throws IOException,ServletException {
 HttpServletRequest req = null;
 if (request instanceof HttpServletRequest) {
  req = (HttpServletRequest) request;
 }
 HttpServletResponse res = null;
 if (response instanceof HttpServletResponse) {
  res = (HttpServletResponse) response;
 }
 if (req != null && res != null) {
  //設定允許傳遞的引數
  res.setHeader("Access-Control-Allow-Headers","Origin,X-Requested-With,Content-Type,Accept,Authorization");
  //設定允許帶上cookie
  res.setHeader("Access-Control-Allow-Credentials","true");
  String origin = Optional.ofNullable(req.getHeader("Origin")).orElse(req.getHeader("Referer"));
  //設定允許的請求來源
  res.setHeader("Access-Control-Allow-Origin",origin);
  //設定允許的請求方法
  res.setHeader("Access-Control-Allow-Methods","GET,POST,PATCH,PUT,DELETE,OPTIONS");
 }
 chain.doFilter(request,response);
 }
 
 @Override
 public void destroy() {
 
 }
 
}

前者ajax請求的時候應該帶上引數

$.ajax({
type: "GET",url: url,xhrFields: {
  withCredentials: true // 攜帶跨域cookie
},processData: false,success: function(data) {
  console.log(data); 
}
});

3、LoginAuthorizationFilter主要是對未登入的使用者進行過濾然後返回json資料給前端,之前遇到的問題就是shiro配置的loginUrl會導致出現302的問題,在前後端分離的專案中,頁面的跳轉應該由前端來進行控制,這裡前端使用的是vue框架,我需要對shiro中未登入的過濾器FormAuthenticationFilter進行重構

package com.hisi.shiro;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;
 
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
 
import com.alibaba.fastjson.JSONObject;
import com.commons.model.YfpjResult;
import com.hisi.mapper.HisiUserMapper;
import com.hisi.model.HisiUser;
import com.hisi.util.Constant;
import com.hisi.util.UserAuthStatusEnum;
 
/**
 * shiro未登入反回狀態碼
 * @author xuguoqin
 * @date 2018年5月10日
 * @version 1.0
 */
public class LoginAuthorizationFilter extends FormAuthenticationFilter {
 
 /**
 * 這個方法是未登入需要執行的方法
 */
 @Override
 protected boolean onAccessDenied(ServletRequest request,ServletResponse response) throws IOException {
 
 HttpServletRequest httpRequest = (HttpServletRequest) request; 
    HttpServletResponse httpResponse = (HttpServletResponse) response; 
 
    Subject subject = getSubject(request,response); 
    if (subject.getPrincipal() == null) { 
     //設定響應頭
 httpResponse.setCharacterEncoding("UTF-8");
 httpResponse.setContentType("application/json");
 //設定返回的資料
 YfpjResult result = YfpjResult.build(UserAuthStatusEnum.UNLOGIN.getCode(),UserAuthStatusEnum.UNLOGIN.getMsg());
 //寫回給客戶端
 PrintWriter out = httpResponse.getWriter();
 out.write(JSONObject.toJSONString(result));
 //重新整理和關閉輸出流
 out.flush();
 out.close();
    } else { 
     //設定響應頭
   httpResponse.setCharacterEncoding("UTF-8");
   httpResponse.setContentType("application/json");
   //設定返回的資料
   YfpjResult result = YfpjResult.build(UserAuthStatusEnum.UNAUTH.getCode(),UserAuthStatusEnum.UNAUTH.getMsg());
   //寫回給客戶端
   PrintWriter out = httpResponse.getWriter();
   out.write(JSONObject.toJSONString(result));
   //重新整理和關閉輸出流
   out.flush();
   out.close();
    } 
    return false; 
 }
}

4.以後在進行前後端分離的專案開發的時候,可以前端封裝一個允許帶cookie的ajax請求,同時封裝一個統一的未登入或者未授權狀態碼的判斷

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。