springboot整合security实现权限控制

慈云数据 2024-05-29 技术支持 22 0

SpringSecurity

什么是SpringSecurity

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

springboot整合security实现权限控制
(图片来源网络,侵删)

Spring Security 为基于J2EE企业应用软件提供了全面安全服务。特别是使用领先的J2EE解决方案-Spring框架开发的企业软件项目。人们使用Spring Security有很多种原因,不过通常吸引他们的是在J2EE Servlet规范或EJB规范中找不到典型企业应用场景的解决方案。特别要指出的是他们不能再

WAR 或 EAR 级别进行移植。这样,如果你更换服务器环境,就要,在新的目标环境进行大量的工作,对你的应用

springboot整合security实现权限控制
(图片来源网络,侵删)

系统进行重新配置安全。使用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
微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon