Spring Security总结(五)

开启权限控制

一、角色控制

RbacAuthorityService.java

这个用于控制访问,通过获取到请求用户的角色权限后,将匹配该角色能够访问的url,若可以访问,则赋予权限,否则拒绝。

package com.uestc.labelproject.config;

import com.uestc.labelproject.entity.SelfUserDetails;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.CancellationException;

/**
 * @Auther: kiritoghy
 * @Desc:角色控制
 * @Date: 19-7-23 下午8:11
 */
@Slf4j
@Component("rbacauthorityservice")
public class RbacAuthorityService {
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        log.info("try get permission");
        Object userInfo = authentication.getPrincipal();

        boolean hasPermission  = false;

        if (userInfo instanceof UserDetails) {

            Collection<? extends GrantedAuthority> set = ((UserDetails) userInfo).getAuthorities();
            Iterator<? extends GrantedAuthority> iterator = set.iterator();
            while(iterator.hasNext()){
                String role = iterator.next().getAuthority();
                // 这些 url 都是要登录后才能访问,且其他的 url 都不能访问!
                Set<String> urls = new HashSet();

                //获取资源
                switch (role){
                    case "ROLE_ADMIN":
                        urls.add("/api/admin/**");
                        break;
                    case "ROLE_USER":
                        urls.add("/api/user/**");
                        break;
                    case "ROLE_REVIEWER":
                        urls.add("/api/reviewer/**");
                        break;
                }

                AntPathMatcher antPathMatcher = new AntPathMatcher();
                for (String url : urls) {
                    if (antPathMatcher.match(url, request.getRequestURI())) {
                        hasPermission = true;
                        break;
                    }
                }
            }
            log.info("url:{},取得permission:{}",request.getRequestURI(),hasPermission);
            return hasPermission;
        }
        else {
            log.info("url:{},取得permission:{}",request.getRequestURI(),false);
            return false;
        }
    }
}

二、配置Spring Security

这个便是spring security的自定义配置选项,将之前实现的接口或者filter加入到配置中

WebSecurityConfig.java

package com.uestc.labelproject.config;

import com.uestc.labelproject.entity.SelfUserDetails;
import com.uestc.labelproject.service.impl.SelfUserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @Auther: kiritoghy
 * @Desc:权限配置
 * @Date: 19-7-23 下午1:32
 */
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
    @Autowired
    CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
    @Autowired
    CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
    @Autowired
    JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Autowired
    SelfUserServiceImpl selfUserService;
    @Autowired
    CustomAuthenticationProvider customAuthenticationProvider;
    @Autowired
    CustomAccessDeniedHandler customAccessDeniedHandler;
    @Autowired
    CustomLogoutSuccessHandler customLogoutSuccessHandler;

    @Override
    public void configure(WebSecurity web) throws Exception {
        //ignore
        web.ignoring().antMatchers("/test/**");
        web.ignoring().antMatchers("/image/**","/thumb/**", "/video/**", "/videos/**");
    }
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
        auth.userDetailsService(selfUserService).passwordEncoder(new BCryptPasswordEncoder());
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //http.authorizeRequests().antMatchers("/test/**").permitAll();
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 使用 JWT,关闭token
                .and()

                .httpBasic().authenticationEntryPoint(customAuthenticationEntryPoint)

                .and()
                .authorizeRequests()//定义哪些URL需要被保护、哪些不需要被保护
                .anyRequest().access("@rbacauthorityservice.hasPermission(request, authentication)")
                .and()
                .formLogin().loginProcessingUrl("/login")
                .successHandler(customAuthenticationSuccessHandler)
                .failureHandler(customAuthenticationFailureHandler)
                .permitAll()

                .and()
                .logout()//默认注销行为为logout
                .logoutUrl("/logout")
                .logoutSuccessHandler(customLogoutSuccessHandler)
                .permitAll();
        http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler); // 无权访问 JSON 格式的数据
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        http.cors();
    }
}

三、静态资源映射

通过对WebMvcConfigurer的实现,来将资源映射到对应路径

WebMvcConfig.java

package com.uestc.labelproject.config;

import com.uestc.labelproject.utils.FileUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Auther: kiritoghy
 * @Date: 19-7-30 上午11:26
 * @Desc: 图片路径映射
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry){
        registry.addResourceHandler("/image/**").addResourceLocations("file:"+ FileUtil.IMAGE_DIC);
        registry.addResourceHandler("/thumb/**").addResourceLocations("file:"+ FileUtil.IMAGE_S_DIC);
        registry.addResourceHandler("/video/**").addResourceLocations("file:" + FileUtil.VIDEO_DIC);
        registry.addResourceHandler("/videos/**").addResourceLocations("file:" + FileUtil.VIDEO_S_DIC);
    }
}

四、跨域设置

因为该项目是前后端分离项目,因此在部署后存在跨域的问题,因此需要对跨域问题进行配置

GlobalCorsConfig.java

package com.uestc.labelproject.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

/**
 * @Auther: kiritoghy
 * @Date: 19-7-30 下午4:05
 * @Desc:跨域
 */
@Configuration
public class GlobalCorsConfig {
    @Bean
    public CorsConfigurationSource corsConfigurationSource(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setAllowedMethods(Arrays.asList("POST","GET","PUT","DELETE","OPTIONS"));
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addExposedHeader("Authorization");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",corsConfiguration);
        return source;
    }
}

小结

到此基本的Spring Security就配置完成了,利用redis和jwt进行token的生成和管理,也是自己对于spring security的一次尝试,在此记录,以后要用可以参考。