使用 Spring Security 启用对 @RestController 的访问

Posted

技术标签:

【中文标题】使用 Spring Security 启用对 @RestController 的访问【英文标题】:Enable access for @RestController using spring security 【发布时间】:2018-06-05 00:17:01 【问题描述】:

我有一个使用 spring security basic auth 实现的项目。映射了四个访问角色。 "ADMIN" 映射到 "/admin/**"

我可以登录并访问WebContent/admin 文件夹中的所有html 资源。发布我使用@RestController@RequestMapping("/admin/users")创建了一些服务

问题是我无法访问任何宁静的服务。错误是404。所有 restful 服务类都存在于 war 文件中。我确定存在一些配置问题。有什么想法吗?

我的代码spinet:

安全配置.java

package com.dev.portal.mvc.configs;
import org.springframework.beans.factory.annotation.Autowired;
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.web.util.matcher.AntPathRequestMatcher;

import com.dev.portal.constants.UserRoles;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired
    CustomSuccessHandler customSuccessHandler;
    @Autowired
    AppUserDetailsService appUserDetailsService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
        auth.userDetailsService(appUserDetailsService);
    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        String[] allRoles =  UserRoles.ADMIN, UserRoles.ORG_ADMIN, UserRoles.CATALOG_ADMIN, UserRoles.DEVELOPER ;
        http.authorizeRequests().antMatchers("/").hasAnyRole(allRoles)
            .antMatchers("/admin/**").hasRole(UserRoles.ADMIN)
            .antMatchers("/org_admin/**").hasRole(UserRoles.ORG_ADMIN)
            .antMatchers("/catalog_admin/**").hasRole(UserRoles.CATALOG_ADMIN)
            .antMatchers("/developer/**").hasRole(UserRoles.DEVELOPER)
            .and().formLogin().successHandler(customSuccessHandler)
            .and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).permitAll();
        http.httpBasic();
        http.csrf().disable();
    


MvcConfig.java

package com.dev.portal.mvc.configs;
import static com.mongodb.MongoClientOptions.builder;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;

import com.dev.portal.commons.CertificateHelper;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;

@PropertySource( "classpath:mongodb.properties" )
@ComponentScan(basePackages = "com.dev.portal.services.orgadmin")
public class MvcConfig 

    private @Value("$db.ip") String db_ip;
    private @Value("$db.port") String db_port;
    private @Value("$db.name") String db_name;
    private @Value("$db.user") String db_user;
    private @Value("$db.password") String db_password;
    private @Value("$db.admin") String db_admin;

    @Bean
    public CustomSuccessHandler getCustomSuccessHandler() 
        return new CustomSuccessHandler();
    

    @Bean
    public AppUserDetailsService getAppUserDetailsService() 
        return new AppUserDetailsService();
    

    @Bean
    public MongoTemplate getMongoTemplate() 
        MongoClient mongoClient =
                new MongoClient(new ServerAddress(db_ip, Integer.parseInt(db_port)),
                        Arrays.asList(MongoCredential.createScramSha1Credential(db_user, db_admin,
                                db_password.toCharArray())),
                        builder().sslEnabled(true).socketFactory(CertificateHelper.validateCert(db_ip))
                                .sslInvalidHostNameAllowed(true).build());
        return new MongoTemplate(new SimpleMongoDbFactory(mongoClient, db_name));
    


UserModelService.java

package com.dev.portal.services.orgadmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.dev.portal.dao.client.UserAuthDaoClient;
import com.dev.portal.models.UserAuthModel;

@RestController
@RequestMapping("/org_admin/user")
public class UserModelService 

    @Autowired
    MongoTemplate mongoTemplate;
    UserAuthDaoClient userAuthDaoClient = new UserAuthDaoClient(mongoTemplate);

    @RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json")
    public UserAuthModel getUserAuthModelByUsername(@RequestParam String username) 
        return userAuthDaoClient.getUserAuthModelByUsername(username);
    

    @RequestMapping(value = "", method = RequestMethod.POST, produces = "application/json")
    public UserAuthModel saveOrUpdateUserAuthModel(@RequestBody UserAuthModel userAuthModel) 
        return userAuthDaoClient.saveOrUpdateUserAuthModel(userAuthModel);
    


WebApplicationInitializer.java

package com.dev.portal.mvc.configs;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class WebApplicationInitializer extends AbstractSecurityWebApplicationInitializer 

    public WebApplicationInitializer() 
        super(MvcConfig.class, SecurityConfig.class);
    


【问题讨论】:

【参考方案1】:

我修改了MvcConfig.javaWebApplicationInitializer.java,如下所示,它表示工作正常。我仍在寻找另一种方法,因为我正在使用已弃用类的扩展。

MvcConfig.java

package com.dev.portal.mvc.configs;

import static com.mongodb.MongoClientOptions.builder;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.dev.portal.commons.CertificateHelper;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;

@SuppressWarnings("deprecation")
@EnableWebMvc
@PropertySource( "classpath:mongodb.properties" )
@ComponentScan(basePackages = "com.dev.portal.services.**")
public class MvcConfig extends WebMvcConfigurerAdapter 

    private @Value("$db.ip") String db_ip;
    private @Value("$db.port") String db_port;
    private @Value("$db.name") String db_name;
    private @Value("$db.user") String db_user;
    private @Value("$db.password") String db_password;
    private @Value("$db.admin") String db_admin;

    @Bean
    public CustomSuccessHandler getCustomSuccessHandler() 
        return new CustomSuccessHandler();
    

    @Bean
    public AppUserDetailsService getAppUserDetailsService() 
        return new AppUserDetailsService();
    

    @Bean
    public MongoTemplate getMongoTemplate() 
        MongoClient mongoClient =
                new MongoClient(new ServerAddress(db_ip, Integer.parseInt(db_port)),
                        Arrays.asList(MongoCredential.createScramSha1Credential(db_user, db_admin,
                                db_password.toCharArray())),
                        builder().sslEnabled(true).socketFactory(CertificateHelper.validateCert(db_ip))
                                .sslInvalidHostNameAllowed(true).build());
        return new MongoTemplate(new SimpleMongoDbFactory(mongoClient, db_name));
    

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) 
        configurer.enable();
    


WebApplicationInitializer.java

package com.dev.portal.mvc.configs;

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class WebApplicationInitializer extends AbstractSecurityWebApplicationInitializer 

    public WebApplicationInitializer() 
        super(MvcConfig.class, SecurityConfig.class);
    

    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) 
        servletContext.addListener(new net.bull.javamelody.SessionListener());
        servletContext.addFilter("CorsFilter", CORSFilter.class).addMappingForUrlPatterns(null, false, "/*");
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dev-portal-dispatcher",
                new DispatcherServlet(new AnnotationConfigWebApplicationContext()));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/*");
    


CORSFilter.java

package com.dev.portal.mvc.configs;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

public class CORSFilter implements Filter 

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException 
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");
        chain.doFilter(req, res);
    

    @Override
    public void init(FilterConfig filterConfig) 
    

    @Override
    public void destroy() 
    


【讨论】:

以上是关于使用 Spring Security 启用对 @RestController 的访问的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Spring Security 中为 oauth/token 端点启用 CORS

如何在 Spring Boot 中使用 Spring Security 启用 CORS

如何在 Spring Boot 中在 Spring Security 级别启用 CORS [关闭]

如何使用 Spring MVC 和 Spring Security 为资源处理程序启用 HTTP 缓存

如何使用 XML 使用 Spring Security Oauth2 启用 /oauth/check_token

如何解决在使用 Spring Boot 和 Spring Security 启用 CSRF 后无法正常工作的登录问题?