springboot security基于注解配置权限与CAS单点登录配置。

来源:互联网 发布:台湾处境现状 知乎 编辑:程序博客网 时间:2024/06/05 09:55

1.因产品需求方的要求,我经过考察,使用现今流行的springboot框架,security权限配置,刚开始碰到不少坑,后来慢慢琢磨,其实发现也就那么一回事。

2.看本文章前,需要有点springboot对于注解基础,否则可能不太理解。

这个是我的基本配置,有部分大家可能用不到,我就说一下基本使用的哪些。

WebConfig这个类继承WebMvcConfigurerAdapter,其实主要是配置拦截器使用的

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private WebDavConfig webDavConfig;
    
    @Autowired
    private UserSecurityInterceptor securityInterceptor;

 

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new BreadCrumbInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(new WorkWXInterceptor()).addPathPatterns("/**");

        .excludePathPatterns("/login","/logout");//配置登录拦截器拦截路径
        
     //   registry.addInterceptor(authInterceptor);  //用于跨域时候拦截判断
    }
    
    @Override  
    public void addCorsMappings(CorsRegistry registry) {  
        registry.addMapping("/**")  
                .allowedOrigins("*")  
                .allowCredentials(true)  
                .allowedMethods("GET", "POST", "DELETE", "PUT")  
                .maxAge(3600);  
    }  

 

    

    @Bean
    public FilterRegistrationBean webDavFilterRegistration() {

        WebDavEngine engine = new WebDavEngine(webDavConfig.getFsPath());

        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(engine.getFilter());
        registration.addUrlPatterns(engine.getResourceRoot());
        registration.setName("webdav");
        registration.setEnabled(webDavConfig.isEnable());
        return registration;

    }

}
主要其实也就一些拦截器配置使用,其它功能其实很少使用到。具体就那样。

主要的权限配置还是如下:

public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

}

这个WebSecurityConfig继承WebSecurityConfigurerAdapter,并重写它的方法来设置安全权限





import mobi.shoumeng.oa.entities.base.config.CasProperties;

/**
 * Created by wuyanzhou
 * Copyright @2017
 */

import mobi.shoumeng.oa.services.auth.UserAuthService;
import mobi.shoumeng.oa.services.workwx.auth.WorkWXAuthFilter;
import mobi.shoumeng.oa.services.workwx.auth.WorkWXAuthProvider;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserAuthService userAuthService;

    @Autowired
    private WorkWXAuthProvider workWXAuthProvider;
    
    @Autowired
    private MyFilterSecurityInterceptor myFilterSecurityInterceptor;
    
    @Autowired  
    private CasProperties casProperties;   //Cas认证
    
    @Autowired
    private UserSecurityInterceptor securityInterceptor;
    
   
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
                .authorizeRequests()
                .antMatchers("/weixin","/favicon.ico", "/js/*","/css/*","/jquery-ui-timepicker-addon/*","/images/*", "/fonts/*", "/caldav", "/carddav", "/files/").permitAll()//这些静态可以全部权限访问
                .anyRequest().authenticated()
                .and()
                //增加企业微信登录处理
                .addFilterAfter(getWorkWXAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .csrf().disable()
                .formLogin().loginPage("/login")//登录页面
                .defaultSuccessUrl("/#/notice/index",true)//默认跳转
                .permitAll()
                .and()
//                .rememberMe()
//                .tokenValiditySeconds(360000)
//                .userDetailsService(userAuthService)
//                .useSecureCookie(true)
//                .and()
                .headers()
                .defaultsDisabled()
                .contentTypeOptions();
          
        http.sessionManagement()   //配置session的功能
        .maximumSessions(1)
        .maxSessionsPreventsLogin(false)  //这个功能很强悍,我这样配置,你的登录会把账号挤出去
        .expiredUrl("/login")
        .sessionRegistry(sessionRegistry());//session的其他注册配置
        
        
        
       http.logout()
       .logoutUrl("/logout")
       .logoutSuccessUrl(casProperties.getCasServerLogoutUrl())  //这个是登出时候跳到单点服务器上面,把单点注销了账号
       .invalidateHttpSession(true)   //初始化
       .clearAuthentication(true)//清除权限
       .invalidateHttpSession(true)
       .permitAll();
        
      http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);

   //   http.exceptionHandling().accessDeniedPage("/Jurisdiction/insufficientAuthority"); //尝试测试
      //session等待时间
     // http.sessionManagement().wait(1800);
      
      http.exceptionHandling()
      .accessDeniedPage("/Jurisdiction/insufficientAuthority")  //当页面没有权限的时候,跳转地方
      .authenticationEntryPoint(casAuthenticationEntryPoint())  //单点登录的认证入口
      .and()  
      .addFilter(casAuthenticationFilter())  //记得添加拦截器
      .addFilterBefore(casLogoutFilter(), LogoutFilter.class)  //添加登出拦截器
      .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);   
     
      
      
    }

    private WorkWXAuthFilter getWorkWXAuthenticationFilter() throws Exception {

        WorkWXAuthFilter filter = new WorkWXAuthFilter();//微信登录设置验证
        filter.setAuthenticationManager(authenticationManager());
        return filter;

    }
    
    
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

        auth
                .userDetailsService(userAuthService)//用户验证
                .passwordEncoder(new ShaPasswordEncoder())//加密算法,使用sh1
                .and()
                .authenticationProvider(workWXAuthProvider);//微信登录的验证入口
      
       
                auth.authenticationProvider(casAuthenticationProvider());  //单点登录验证
    }
    
    // Work around https://jira.spring.io/browse/SEC-2855
    @Bean
    public SessionRegistry sessionRegistry() {
        SessionRegistry sessionRegistry = new SessionRegistryImpl();
        return sessionRegistry;
    }
    @Bean
    public static ServletListenerRegistrationBean httpSessionEventPublisher() {
        return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
    }
    
    
    
    
    
    /**认证的入口*/  
    @Bean  
    public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {  
        CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();  
        casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());  
        casAuthenticationEntryPoint.setServiceProperties(serviceProperties());  
        return casAuthenticationEntryPoint;  
    }  
      
    /**指定service相关信息*/  
    @Bean  
    public ServiceProperties serviceProperties() {  
        ServiceProperties serviceProperties = new ServiceProperties();  
        serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());  
        serviceProperties.setAuthenticateAllArtifacts(true);  
        return serviceProperties;  
    }  
      
    /**CAS认证过滤器*/  
    @Bean  
    public CasAuthenticationFilter casAuthenticationFilter() throws Exception {  
        CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();  
        casAuthenticationFilter.setAuthenticationManager(authenticationManager());  
        casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());  
        return casAuthenticationFilter;  
    }  
      
    /**cas 认证 Provider*/  
    @Bean  
    public CasAuthenticationProvider casAuthenticationProvider() {  
        CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();  
      //  casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());  
         casAuthenticationProvider.setUserDetailsService(userAuthService);//这个是我自己配置,根据自己需要配置
        //casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //这里只是接口类型,实现的接口不一样,都可以的。  
        casAuthenticationProvider.setServiceProperties(serviceProperties());  
        casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());  
        casAuthenticationProvider.setKey("casAuthenticationProviderKey");  
        return casAuthenticationProvider;  
    }  
      
//   @Bean
//    public UserDetailsService UserDetailsService(){
//        return new UserAuthService();
//    }
      
//    /**用户自定义的AuthenticationUserDetailsService*/  
//    @Bean  
//    public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService(){  
//        return new UserAuthService();  
//    }  
      
    @Bean  
    public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {  //一种校验方式
        return new Cas20ServiceTicketValidator(casProperties.getCasServerUrl());  
    }  
      
    /**单点登出过滤器*/  
    @Bean  
    public SingleSignOutFilter singleSignOutFilter() {  
        SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();  
        singleSignOutFilter.setCasServerUrlPrefix(casProperties.getCasServerUrl());  
        singleSignOutFilter.setIgnoreInitConfiguration(true);  
        return singleSignOutFilter;  
    }  
      
    /**请求单点退出过滤器*/  
    @Bean  
    public LogoutFilter casLogoutFilter() {  //这个地方要注意,service需要你在单点服务器上面配置那边配置跳转,会跳转你需要的页面,否则跳不回来
        LogoutFilter logoutFilter = new LogoutFilter(casProperties.getCasServerLogoutUrl()+"?service=" + casProperties.getAppServerUrl() + casProperties.getAppLoginUrl(), new SecurityContextLogoutHandler());  
        logoutFilter.setFilterProcessesUrl(casProperties.getAppLogoutUrl());  
        return logoutFilter;  
    }  
}  
    
    

@Component
public class UserAuthService implements UserDetailsService{//, AuthenticationUserDetailsService<CasAssertionAuthenticationToken>  {

    @Autowired
    private UserRepository userRepository;
  
    
    @Autowired
    DepartementServiceImpl departementServiceImpl;
    
    @Autowired
    PepopleServiceImpl  pepopleServiceImpl;
    
    @Autowired
    CommentSession commentSession;
    
    @Autowired
    HttpServletRequest request;
    
    @Autowired
    UserRoleServiceImpl userRoleServiceImpl;
    

    

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        List<GrantedAuthority> grantedAuthorities = new ArrayList <>();
        User user = userRepository.findByLoginAccount(s);
        if(user.getUseif()!=1){
            return null;
        }
        UserRole userRole = user.getUserRole();
        UserRole findByUserRole = userRoleServiceImpl.findByUserRole(userRole.getId());
    //     System.out.println("测试角色"+userRole.getName());
        Set<UserPermission> userPermissions = findByUserRole.getUserPermissions();
        for(UserPermission se:userPermissions){
            // System.out.println("测试列表"+se.getName());
             GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(se.getName());
             //1:此处将权限信息添加到 GrantedAuthority 对象中,在后面进行全权限验证时会使用GrantedAuthority 对象。
             grantedAuthorities.add(grantedAuthority);
        }
       
        if (Objects.isNull(user)) {
            
            
            throw new UsernameNotFoundException(String.format("用户名[%s]未找到", s));
        }
   
        org.springframework.security.core.userdetails.User sysuser=new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),grantedAuthorities);
         return sysuser;

    }


上面的权限必须用户表必须实现接口User implements UserDetails, Serializable

本人的权限是直接在UserDetails设置,这样避免一些实体类上的问题。权限是根据你的角色里面资源加载,把你的资源URL匹配。

其它的权限验证和网上很多资料差不多,就是配置一下过滤器过滤URL,把每个你配置URL判断是否该资源有没有权限问题等。

 public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {

        if(null== configAttributes || configAttributes.size() <=0) {
            return;
        }
        ConfigAttribute c;
        String needRole;
        for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
            c = iter.next();
            needRole = c.getAttribute();
            for(GrantedAuthority ga : authentication.getAuthorities()) {//authentication 为在注释1 中循环添加到 GrantedAuthority 对象中的权限信息集合
                if(needRole.trim().equals(ga.getAuthority())) {
                    return;
                }
            }
        }
  

总体上讲的可能不是很全面,但是基本的配置已经有注解和讲说。可能有部分没有复制上去,不过网上已经很多资料可以查阅,我的方法其实主要配置已经是非常完善。

有什么技术上的问题,也可以加我的QQ询问我。可能平时不在线,也可以留言。。一位开发者的分享。






原创粉丝点击