Shiro和SpringBoot集成前后端分离登陆验证和权限验证接口302获取不到返回结果的问题

it2022-05-09  42

1、Shiro相关的依赖

<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.crazycake</groupId> <artifactId>shiro-redis</artifactId> <version>3.2.3</version> </dependency>

2、重写登陆验证过滤器authc,继承 org.apache.shiro.web.filter.authc.FormAuthenticationFilter

import cn.gov.chinatax.beijing.entity.base.JsonResult; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import org.apache.shiro.web.util.WebUtils; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class CustomFormAuthenticationFilter extends FormAuthenticationFilter { /** * 屏蔽OPTIONS请求 */ @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { boolean accessAllowed = super.isAccessAllowed(request, response, mappedValue); if (!accessAllowed) { // 判断请求是否是options请求 String method = WebUtils.toHttp(request).getMethod(); if (StringUtils.equalsIgnoreCase("OPTIONS", method)) { return true; } } return accessAllowed; } /** * 解决未登录302问题 * @param request * @param response * @return * @throws Exception */ @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { if (isLoginRequest(request, response)) { if (isLoginSubmission(request, response)) { return executeLogin(request, response); } else { return true; } } else { // 返回固定的JSON串 WebUtils.toHttp(response).setContentType("application/json; charset=utf-8"); WebUtils.toHttp(response).getWriter().print(JsonResult.json(JsonResult.unlogin())); return false; } } }

3、重写权限验证过滤器,继承 org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

import cn.gov.chinatax.beijing.entity.base.JsonResult; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter; import org.apache.shiro.web.util.WebUtils; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.IOException; /** * 自定义权限验证过滤器 */ public class CustomPermissionsAuthorizationFilter extends PermissionsAuthorizationFilter { /** * 根据请求接口路径进行验证 * @param request * @param response * @param mappedValue * @return * @throws IOException */ @Override public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException { // 获取接口请求路径 String servletPath = WebUtils.toHttp(request).getServletPath(); mappedValue = new String[]{servletPath}; return super.isAccessAllowed(request, response, mappedValue); } /** * 解决权限不足302问题 * @param request * @param response * @return * @throws IOException */ @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException { Subject subject = getSubject(request, response); if (subject.getPrincipal() == null) { saveRequestAndRedirectToLogin(request, response); } else { WebUtils.toHttp(response).setContentType("application/json; charset=utf-8"); WebUtils.toHttp(response).getWriter().print(JsonResult.json(JsonResult.unauthorized())); } return false; } }

4、重写sessionId获取方法,继承 org.apache.shiro.web.session.mgt.DefaultWebSessionManager

import org.apache.commons.lang3.StringUtils; import org.apache.shiro.web.servlet.ShiroHttpServletRequest; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.apache.shiro.web.util.WebUtils; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.Serializable; /** * 自定义SessionId获取路径 */ public class CustomDefaultWebSessionManager extends DefaultWebSessionManager { @Override protected Serializable getSessionId(ServletRequest request, ServletResponse response) { String sessionId = WebUtils.toHttp(request).getHeader("Authorization"); // 如果请求头中有 Authorization 则其值为sessionId if (StringUtils.isNotBlank(sessionId)) { request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, ShiroHttpServletRequest.URL_SESSION_ID_SOURCE); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE); return sessionId; } else { //否则按默认规则从cookie取sessionId return super.getSessionId(request, response); } } }

5、Shiro配置类

import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.mgt.SessionManager; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.crazycake.shiro.RedisCacheManager; import org.crazycake.shiro.RedisManager; import org.crazycake.shiro.RedisSessionDAO; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.Map; /** * Shiro配置类 */ @Configuration public class ShiroConfiguration { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.timeout}") private int timeout; @Value("${spring.redis.database}") private int database; @Value("${spring.redis.password}") private String password; @Bean public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); // 设置自定义的过滤器 Map<String, Filter> filters = shiroFilterFactoryBean.getFilters(); filters.put("authc", new CustomFormAuthenticationFilter()); filters.put("perms", new CustomPermissionsAuthorizationFilter()); Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap(); //注意过滤器配置顺序 filterChainDefinitionMap.put("/xxx", "anon"); // 不需要登录 filterChainDefinitionMap.put("/yyy", "authc"); // 需要登录不需要验证权限 filterChainDefinitionMap.put("/**", "authc,perms"); // 需要登录也需要验证权限 shiroFilterFactoryBean.setLoginUrl("/"); shiroFilterFactoryBean.setUnauthorizedUrl("/"); return shiroFilterFactoryBean; } /** * 凭证匹配器 * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了 * ) * @return */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5"); //散列算法:这里使用MD5算法; hashedCredentialsMatcher.setHashIterations(2); //散列的次数,比如散列两次,相当于 md5(md5("")); return hashedCredentialsMatcher; } @Bean public ShiroRealm shiroRealm() { ShiroRealm shiroRealm = new ShiroRealm(); shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return shiroRealm; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); // 自定义session管理 使用redis securityManager.setSessionManager(sessionManager()); // 自定义缓存实现 使用redis securityManager.setCacheManager(cacheManager()); return securityManager; } //自定义sessionManager @Bean public SessionManager sessionManager() { CustomDefaultWebSessionManager customDefaultWebSessionManager = new CustomDefaultWebSessionManager(); customDefaultWebSessionManager.setSessionDAO(redisSessionDAO()); return customDefaultWebSessionManager; } /** * 配置shiro redisManager * 使用的是shiro-redis开源插件 * @return */ public RedisManager redisManager() { RedisManager redisManager = new RedisManager(); redisManager.setHost(host + ":" + port); redisManager.setDatabase(database); redisManager.setTimeout(timeout); redisManager.setPassword(password); return redisManager; } /** * cacheManager 缓存 redis实现 * 使用的是shiro-redis开源插件 * @return */ @Bean public RedisCacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); return redisCacheManager; } /** * RedisSessionDAO shiro sessionDao层的实现 通过redis * 使用的是shiro-redis开源插件 */ @Bean public RedisSessionDAO redisSessionDAO() { RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); return redisSessionDAO; } }

 


最新回复(0)