`

springboot整合shiro

 
阅读更多

 

    因前后多个项目中使用的到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、完成。

 

 

  • 大小: 222.6 KB
分享到:
评论

相关推荐

    SpringBoot整合Shiro示例实现动态权限加载更新+Session共享+单点登录

    SpringBoot整合Shiro示例实现动态权限加载更新+Session共享+单点登录 SpringBoot整合Shiro示例实现动态权限加载更新+Session共享+单点登录 SpringBoot整合Shiro示例实现动态权限加载更新+Session共享+单点登录 ...

    SpringBoot整合Shiro后实现免密登录

    SpringBoot整合Shiro后实现免密登录 1,说明一下步骤,需要在原来基础新增三个文件 2,新增CustomToken,重写UsernamePasswordToken免密登录调用方法和密码登录调用方法都在里面。 3,新增...

    SpringBoot整合shiro项目静态资源

    SpringBoot整合shiro项目静态资源

    SpringBoot-Shiro整合权限管理源码

    SpringBoot整合Shiro使得权限管理变得简单易行,它提供了灵活的认证和授权机制。通过阅读和理解`springboot-shiro`的源码,开发者可以快速上手,并在实际项目中实现高效的权限管理功能。记得在实际操作中,根据项目...

    springboot整合shiro.zip

    SpringBoot整合Shiro是一个常见的Java Web开发任务,用于实现用户认证和授权。SpringBoot以其便捷的集成特性,简化了项目的构建过程,而Apache Shiro则是一个强大且易用的安全框架,能够处理用户登录、权限控制等...

    springboot整合shiro的demo.zip

    springboot整合shiro的demo Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和...

    springboot整合shiro视频教程

    springboot整合shiro视频教程,实现登陆认证,权限认证

    springboot整合shiro视频

    《SpringBoot整合Shiro实战详解》 在Java开发领域,SpringBoot因其简洁高效的特性,已经成为构建Web应用的首选框架。而Shiro作为一款强大的安全管理框架,提供了身份验证、授权、会话管理和加密等功能,常被用于...

    项目演示:springboot整合shiro.zip

    SpringBoot整合Shiro是一个常见的Java Web开发任务,用于实现用户认证和授权功能。SpringBoot以其简洁的配置和快速的启动时间受到广大开发者的喜爱,而Apache Shiro则是一个强大且易用的安全框架,能帮助开发者处理...

    springboot整合shiro,redis缓存session

    为实现Web应用的分布式集群部署,要解决登录session的统一。本文利用shiro做权限控制,redis做session存储,结合spring boot快速配置实现session共享。

    springboot整合shiro实践操作

    springboot整合shiro实践操作

    springboot整合shiro登录失败次数限制功能的实现代码

    主要介绍了springboot整合shiro-登录失败次数限制功能,实现此功能如果是防止坏人多次尝试,破解密码的情况,所以要限制用户登录尝试次数,需要的朋友可以参考下

    SpringBoot整合shiro、redis集成mybatis

    **SpringBoot整合Shiro** 1. **Shiro配置**:在SpringBoot项目中,我们需要引入Shiro的依赖,并创建一个Shiro配置类。配置类中会包括安全过滤器链的设置,如anon(匿名访问)、authc(身份验证)等,以及Realm的...

    SpringBoot整合Shiro与Thymeleaf-权限管理实战视频

    ### SpringBoot整合Shiro与Thymeleaf-权限管理实战 #### 一、Spring Boot简介 Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目标是简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式(默认...

    SpringBoot_Shiro_JWT_Redis:SpringBoot整合Shiro、JWT和Redis实现token登录授权验证以及token刷新

    SpringBoot整合Shiro、JWT和Redis实现token登录授权验证以及token刷新 前端代码为一个博客页面,使用了Semantic UI框架结合thymeleaf模板 SpringBoot结合JWT+Shiro+Redis实现token无状态登录授权 [TOC] 一、引言 ​ ...

    SpringBoot整合Shiro权限框架

    SpringBoot整合Shiro权限框架是将SpringBoot与Apache Shiro这两个流行的技术栈结合,用于实现Web应用的安全控制和用户权限管理。SpringBoot以其简洁的配置和快速的开发体验深受开发者喜爱,而Shiro则是一个轻量级的...

    SpringBoot整合Shiro,实现从数据库加载权限、权限的动态更新、Session共享

    2. **SpringBoot整合Shiro**: - **依赖配置**:首先在`pom.xml`文件中添加Shiro的依赖,确保SpringBoot项目能够识别和使用Shiro的相关库。 - **配置Shiro Realm**:创建自定义的`Realm`,继承自`AuthorizingRealm...

Global site tag (gtag.js) - Google Analytics