SpringSecurity
什么是SpringSecurity
Spring Security 的前身是 Acegi Security ,是 Spring 项目组中用来提供安全认证服务的框架。(官网地址)

(图片来源网络,侵删)
Spring Security 为基于J2EE企业应用软件提供了全面安全服务。特别是使用领先的J2EE解决方案-Spring框架开发的企业软件项目。人们使用Spring Security有很多种原因,不过通常吸引他们的是在J2EE Servlet规范或EJB规范中找不到典型企业应用场景的解决方案。特别要指出的是他们不能再
WAR 或 EAR 级别进行移植。这样,如果你更换服务器环境,就要,在新的目标环境进行大量的工作,对你的应用

(图片来源网络,侵删)
系统进行重新配置安全。使用Spring Security 解决了这些问题,也为你提供很多有用的,完全可以指定的其他安
全特性。安全包括两个主要操作。
- “认证”,是为用户建立一个他所声明的主体。主体一般是指用户,设备或可以在你系统中执行动作的其他系
统。(可以将主体当前权限框架自己的session,认证其实就是登录操作,并将登录成功的数据信息存入主体)
- “授权”,指的是一个用户能否在你的应用中执行某个操作,在到达授权判断之前,身份的主题已经由身份验证
过程建立了。(查询是否对应权限,授权其实就是在认证之后请求需要权限的资源时,查询数据库在主体中保存对应权限数据)
这些概念是通用的,不是Spring Security特有的。
SpringBoot整合SpringSecurity
SpringSecurity配置类 WebSecurityConfig.java
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import javax.annotation.Resource; // @EnableGlobalMethodSecurity(jsr250Enabled = true) //开启jsr250注解 // @EnableGlobalMethodSecurity(securedEnabled = true) //开启secured注解 // @EnableGlobalMethodSecurity(prePostEnabled = true) //开启表达式注解 @EnableWebSecurity @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Resource private UsersService usersService; //注入自定义权限加载器 @Autowired MyInvocationSecurityMetadataSourceService myInvocationSecurityMetadataSourceService; //注入自定义决策管理器 @Autowired MyAccessDecisionManager myAccessDecisionManager; //注入自定义权限拦截器 @Autowired MyFilterSecurityInterceptor myFilterSecurityInterceptor; @Override protected void configure(HttpSecurity http) throws Exception { http .headers() //同源策略 如果页面使用iframe需要配置 否则不能使用 .frameOptions().sameOrigin().and() //自定义表单登录页面 .formLogin() //指定登录页面 .loginPage("/login.jsp") //指定登录请求 .loginProcessingUrl("/login") //指定登录请求账号参数 .usernameParameter("username") //指定登录请求密码参数 .passwordParameter("password") //指定登录成功转发请求路径 .successForwardUrl("/page/main.jsp") //指定登录失败请求路径 .failureUrl("/failer.jsp") .and() .logout() //指定退出登录请求路径 .logoutUrl("/logout") //指定退出登录请求后跳转路径 .logoutSuccessUrl("/login.jsp") //是否清除session .invalidateHttpSession(true) .and() //权限配置 .authorizeRequests() //放行 登录页面 .antMatchers("/login.jsp","/failer.jsp").permitAll() //放开 静态资源 .antMatchers("/css/**","/img/**","/js/**","/plugins/**","/layui/**").permitAll() //其他 资源需要拥有对应角色才能访问 //.antMatchers("/**")..hasAnyRole("ROLE_USER","ROLE_ADMIN") //其他 资源需要登录后访问 .anyRequest().authenticated().and() // 配置自定义拦截器 将定义拦截器配置到当前权限框架拦截器链中的指定位置 将其配置在本身的权限认证过滤器之后执行 .addFilterAfter(myFilterSecurityInterceptor, FilterSecurityInterceptor.class) //禁用csrf .csrf() .disable(); //没有权限跳转页面 http.exceptionHandling().accessDeniedPage("/failer.jsp"); } //认证的数据需要使用自定义的UserDetailsService //需要,先去创建一个自定义的UserService @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(usersService).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
自定义权限加载器 MyInvocationSecurityMetadataSourceService.java
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import java.util.*; @Service //授权管理器 //用于当前项目要动态配置的权限信息 //从数据库中取出所有的权限信息 进行配置 //这样当客户请求对应权限时进行权限验证(因为不可能将所有的url都过滤) public class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource { @Autowired //注入权限查询的dao层 private PermissionMapper permissionMapper; private HashMap map =null; /** * 加载权限表中所有权限 */ public void loadResourceDefine(){ map = new HashMap(); Collection array; ConfigAttribute cfg; //动态查询当前数据库中所有的权限 List permissions = permissionMapper.selectAll(); for(Permission permission : permissions) { array = new ArrayList(); cfg = new SecurityConfig(permission.getPermissionName()); //此处只添加了权限的名字,其实还可以添加更多权限的信息,例如请求方法到ConfigAttribute的集合中去。此处添加的信息将会作为MyAccessDecisionManager类的decide的第三个参数。 array.add(cfg); //用权限的getUrl() 作为map的key,用ConfigAttribute的集合作为 value, //实际加载存储的结构为 url->[name1,name2....] //url是进行请求url拦截使用的 name是进行权限验证使用的 //也就是说在用户进行授权时 实际加载的是权限名称 map.put(permission.getUrl(), array); } } //此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。 @Override public Collection getAttributes(Object object) throws IllegalArgumentException { if(map ==null) loadResourceDefine(); //object 中包含用户请求的request 信息 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest(); AntPathRequestMatcher matcher; String resUrl; for(Iterator iter = map.keySet().iterator(); iter.hasNext(); ) { resUrl = iter.next(); matcher = new AntPathRequestMatcher(resUrl); if(matcher.matches(request)) { return map.get(resUrl); } } return null; } @Override public Collection getAllConfigAttributes() { return null; } @Override public boolean supports(Class clazz) { return true; } }
自定义决策管理器 MyAccessDecisionManager.java
权限框架本身是由多个不同功能的过滤器组成的,不同的过滤器负责不同的功能例如认证过滤、静态资源过滤、等 授权过滤也是一样,决策器就是同于判断当前请求的url当前账号是否拥有权限
import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.stereotype.Service; import java.util.Collection; import java.util.Iterator; @Service //决策管理器 public class MyAccessDecisionManager implements AccessDecisionManager { // decide 方法是判定是否拥有权限的决策方法, //authentication 是CustomUserService中循环添加到 GrantedAuthority 对象中的权限信息集合. //object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest(); //configAttributes 为MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。 @Override public void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if(null== configAttributes || configAttributes.size() return; } ConfigAttribute c; String needRole; for(Iterator c = iter.next(); needRole = c.getAttribute(); for(GrantedAuthority ga : authentication.getAuthorities()) {//authentication 为在注释1 中循环添加到 GrantedAuthority 对象中的权限信息集合 if(needRole.trim().equals(ga.getAuthority())) { return; } } } throw new AccessDeniedException("no right"); } @Override public boolean supports(ConfigAttribute attribute) { return true; } @Override public boolean supports(Class
- “授权”,指的是一个用户能否在你的应用中执行某个操作,在到达授权判断之前,身份的主题已经由身份验证