因前后多个项目中使用的到springboot和shiro,多方查阅书籍和博客,在此做一个小小整理,以备后需。好记性不如烂笔头。
一、shiro介绍
略
二、springboot介绍
略
三、整合
1、添加依赖
在pom文件中新增shiro相关的依赖。缓存这里暂且采用ehcache。如果是用redis需要做小部分修改。
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <!-- shiro ehcache --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.3.2</version> </dependency> <!-- shiro标签支持 --> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> <!-- ehchache --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> </dependency>
2、shiro配置
除了以上,在shiroFilter中还需要配置at.pollux.thymeleaf.shiro.dialect.ShiroDialect,为了在thymeleaf里使用shiro的标签的bean
@Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); }
3、ehcache的配置
1、首先得有一个ehcache的xml文件,ehcache.xml(内容略)放到/src/main/resource下,也就是类路径下。
2、需要在applicantion.yml文件中声明
spring: cache: ehcache: config: classpath:config/ehcache.xml
3、启动类上需要加上@EnableCaching注解
项目启动时spring会自动构造net.sf.ehcache.CacheManager对象,在类属性中可以通过@Autowired注解得到该对象。
然后将cacheManager注入到ehCacheManager中。
@Autowired private CacheManager cacheManager; @Bean public EhCacheManager ehCacheManager() { EhCacheManager ehCacheManager = new EhCacheManager(); ehCacheManager.setCacheManager(cacheManager); return ehCacheManager; }
四、前后端分离导致的问题
1、前后端分离,后端只负责返json数据。
后端处理:
需要自定义一个配置类MyWebMvcConfig,实现
org.springframework.web.servlet.config.annotation.WebMvcConfigurer接口。
MyWebMvcConfig里面可以添加很多mvc相关的配置。
@Configuration public class MyWebMvcConfig implements WebMvcConfigurer { /** * 以前写SpringMVC的时候,如果需要访问一个页面,必须要写Controller类,然后再写一个 * 方法跳转到页面,感觉好麻烦,其实重写WebMvcConfigurerAdapter中的addViewControllers方法即可 * 达到效果了 */ @Override public void addViewControllers(ViewControllerRegistry registry) { WebMvcConfigurer.super.addViewControllers(registry); } /** * 添加类型转换器和格式化器 * * @param registry */ @Override public void addFormatters(FormatterRegistry registry) { } /** * 跨域支持(主要看这个) * * @param registry */ @Override public void addCorsMappings(CorsRegistry registry) { List<String> allowedOrigins = new ArrayList<>(); allowedOrigins.add("http://localhost:8983");//前端访问地址 String[] objects = allowedOrigins.toArray(new String[allowedOrigins.size()]); registry.addMapping("/**") .allowCredentials(true) //允许Cookie跨域,在做登录校验的时候有用 .allowedMethods("GET", "POST", "DELETE", "PUT")//允许提交请求的方法,*表示全部允许 .maxAge(3600 * 24)//预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了 .allowedOrigins(objects)//允许向该服务器提交请求的URI,*表示全部允许 .allowedHeaders("*"); //允许的头信息,*标识全部允许 } /** * 添加静态资源--过滤 * * @param registry */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { } /** * 配置消息转换器 * * @param converters */ @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { } /** * 配置拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { // TestInterceptor extends HandlerInterceptorAdapter // registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**"); } }
2、或者另外一种方式:
自定义一个过滤器,添加相关跨域处理
@Component public class CorsFilter implements Filter { final static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CorsFilter.class); public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; HttpServletRequest reqs = (HttpServletRequest) req; response.setHeader("Access-Control-Allow-Origin", reqs.getHeader("Origin")); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with,APPID,token"); response.setHeader("Access-Control-Expose-Headers", "APPID");//允许前端跨域获取的头 chain.doFilter(req, res); } public void init(FilterConfig filterConfig) { } public void destroy() { } }
2、前端
function loginOn(){ var data_={ username:"admin", password:"admin" } $.ajax({ type: "POST", url: "http://192.168.2.240:8091/login", data:data_, xhrFields: { withCredentials: true // 携带跨域cookie }, /*processData: false,*/ //测试时,这个如果带上,返回头Response里面会拿不到Cookie,Cookie里面存放了sessionid success: function(data) { console.log(data); } }); }
3、好的!现在登录正常了。
但是在shiro的配置里面,我们有关于登录页的配置
@Bean ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); ..... }
shiro发现用户没有登录时,会重定向到/login页面。但是,因为前后端是分离的。所以得给前端返一个未登录
的json消息。
跨域重定向不好处理,貌似jsonp可以解决。这个重定向,返回的header里面有一个
Location... 后面跟的是重定向的地址,浏览器是不会去处理的。
所以。需要重写一些东西。我只重写了量个过滤器:
FormAuthenticationFilter和LogoutFilter
并将ShiroFilterFactoryBean里面注册的filter替换成自己的。
MyFormAuthenticationFilter
@Configuration public class MyFormAuthenticationFilter extends FormAuthenticationFilter { private static final Logger log = LoggerFactory.getLogger(MyFormAuthenticationFilter.class); @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { if (isLoginRequest(request, response)) { if (isLoginSubmission(request, response)) { if (log.isTraceEnabled()) { log.trace("Login submission detected. Attempting to execute login."); } return executeLogin(request, response); } else { if (log.isTraceEnabled()) { log.trace("Login page view."); } // allow them to see the login page ;) return true; } } else { if (log.isTraceEnabled()) { log.trace("Attempting to access a path which requires authentication. Forwarding to the " + "Authentication url [" + getLoginUrl() + "]"); } // 认证未通过json返回 HttpServletResponse res = (HttpServletResponse) response; HttpServletRequest req = (HttpServletRequest) request; // 登出json返回 res.setCharacterEncoding("UTF-8"); res.setHeader("Content-type", "application/json;charset=UTF-8"); res.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin")); res.setHeader("Access-Control-Allow-Credentials", "true"); res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); ResponseMsg httpResponse = ResponseMsg.create(Code.NotLogin); res.getWriter().write(JSONObject.toJSONString(httpResponse)); return false; } } }
之前是想在方法里抛出一个自定义的异常类BizException extends RuntimeException。但是发现自定义的
MyExceptionHandler implements HandlerExceptionResolver没法拦截处理到我的异常。所以直接在方法
里,对response做了处理。
同理MyLogoutFilter
public class MyLogoutFilter extends LogoutFilter { @Override protected void issueRedirect(ServletRequest request, ServletResponse response, String redirectUrl) throws Exception { HttpServletResponse res = (HttpServletResponse) response; HttpServletRequest req = (HttpServletRequest) request; // 登出json返回 res.setCharacterEncoding("UTF-8"); res.setHeader("Content-type", "application/json;charset=UTF-8"); res.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin")); res.setHeader("Access-Control-Allow-Credentials", "true"); res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); ResponseMsg httpResponse = ResponseMsg.create(Code.OK); res.getWriter().write(JSONObject.toJSONString(httpResponse)); } }
最后替换:
@Bean ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();//获取filters filters.put("authc", new MyFormAuthenticationFilter());//将自定义 的MyFormAuthenticationFilter注入shiroFilter中 filters.put("logout", new MyLogoutFilter());//将自定义 的MyLogoutFilter注入shiroFilter中 shiroFilterFactoryBean.setSecurityManager(securityManager); ..... }
4、完成。
相关推荐
SpringBoot整合Shiro示例实现动态权限加载更新+Session共享+单点登录 SpringBoot整合Shiro示例实现动态权限加载更新+Session共享+单点登录 SpringBoot整合Shiro示例实现动态权限加载更新+Session共享+单点登录 ...
SpringBoot整合Shiro后实现免密登录 1,说明一下步骤,需要在原来基础新增三个文件 2,新增CustomToken,重写UsernamePasswordToken免密登录调用方法和密码登录调用方法都在里面。 3,新增...
SpringBoot整合shiro项目静态资源
SpringBoot整合Shiro使得权限管理变得简单易行,它提供了灵活的认证和授权机制。通过阅读和理解`springboot-shiro`的源码,开发者可以快速上手,并在实际项目中实现高效的权限管理功能。记得在实际操作中,根据项目...
SpringBoot整合Shiro是一个常见的Java Web开发任务,用于实现用户认证和授权。SpringBoot以其便捷的集成特性,简化了项目的构建过程,而Apache Shiro则是一个强大且易用的安全框架,能够处理用户登录、权限控制等...
springboot整合shiro的demo Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和...
springboot整合shiro视频教程,实现登陆认证,权限认证
《SpringBoot整合Shiro实战详解》 在Java开发领域,SpringBoot因其简洁高效的特性,已经成为构建Web应用的首选框架。而Shiro作为一款强大的安全管理框架,提供了身份验证、授权、会话管理和加密等功能,常被用于...
SpringBoot整合Shiro是一个常见的Java Web开发任务,用于实现用户认证和授权功能。SpringBoot以其简洁的配置和快速的启动时间受到广大开发者的喜爱,而Apache Shiro则是一个强大且易用的安全框架,能帮助开发者处理...
为实现Web应用的分布式集群部署,要解决登录session的统一。本文利用shiro做权限控制,redis做session存储,结合spring boot快速配置实现session共享。
springboot整合shiro实践操作
主要介绍了springboot整合shiro-登录失败次数限制功能,实现此功能如果是防止坏人多次尝试,破解密码的情况,所以要限制用户登录尝试次数,需要的朋友可以参考下
**SpringBoot整合Shiro** 1. **Shiro配置**:在SpringBoot项目中,我们需要引入Shiro的依赖,并创建一个Shiro配置类。配置类中会包括安全过滤器链的设置,如anon(匿名访问)、authc(身份验证)等,以及Realm的...
### SpringBoot整合Shiro与Thymeleaf-权限管理实战 #### 一、Spring Boot简介 Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目标是简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式(默认...
SpringBoot整合Shiro、JWT和Redis实现token登录授权验证以及token刷新 前端代码为一个博客页面,使用了Semantic UI框架结合thymeleaf模板 SpringBoot结合JWT+Shiro+Redis实现token无状态登录授权 [TOC] 一、引言 ...
SpringBoot整合Shiro权限框架是将SpringBoot与Apache Shiro这两个流行的技术栈结合,用于实现Web应用的安全控制和用户权限管理。SpringBoot以其简洁的配置和快速的开发体验深受开发者喜爱,而Shiro则是一个轻量级的...
2. **SpringBoot整合Shiro**: - **依赖配置**:首先在`pom.xml`文件中添加Shiro的依赖,确保SpringBoot项目能够识别和使用Shiro的相关库。 - **配置Shiro Realm**:创建自定义的`Realm`,继承自`AuthorizingRealm...