基于注释的REST API Spring安全性

时间:2016-03-21 19:56:11

标签: java spring rest spring-mvc spring-security

我一直在尝试创建一个使用Spring安全保护的rest api

有关架构详细信息,请参阅此链接:Spring Security with REST architecture

但是,在我的实施过程中,我面临以下问题:

  

异常启动过滤器springSecurityFilterChain

我的应用程序实现如下:

@EnableWebMvc
@Configuration
@ComponentScan({ "com.ws.service.*" })
public class AppConfig extends Application {
 ...
}

CustomJDBCDaoImpl

public class CustomJDBCDaoImpl extends JdbcDaoImpl {

    public CustomJDBCDaoImpl() {
        // TODO Auto-generated constructor stub
        super();

    }

    private DataSource getDataSourceFromJndi() {
        ...
    }

    @Override
    protected List<GrantedAuthority> loadGroupAuthorities(String username) {
     ...
    }

    @Override
    public UserDetails loadUserByUsername(String username) {
         ...
    }

    private UpUser findUserByScreenName(String userName) {
         ...
    }

    private ResultSet executeQuery(String sql){
         ...
    }
}

Source code for Stateless Authentication Filter

无状态身份验证安全配置

@EnableWebSecurity
@Configuration
@Order(1)
public class StatelessAuthenticationSecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private TokenAuthenticationService tokenAuthenticationService;

    public StatelessAuthenticationSecurityConfig() {
        super(true);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .exceptionHandling().and()
                .anonymous().and()
                .servletApi().and()
                .headers().cacheControl().and()
                .authorizeRequests()

                //allow anonymous resource requests
                .antMatchers("/").permitAll()
                .antMatchers("/favicon.ico").permitAll()
                .antMatchers("/resources/**").permitAll()

                //allow anonymous POSTs to login
                .antMatchers(HttpMethod.POST, "/api/login").permitAll()

                //allow anonymous GETs to API
                .antMatchers(HttpMethod.GET, "/api/**").permitAll()

                //defined Admin only API area
                .antMatchers("/admin/**").hasRole("ADMIN")

                //all other request need to be authenticated
                .anyRequest().hasRole("USER").and()             

                // custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
                .addFilterBefore(new StatelessLoginFilter("/api/login", tokenAuthenticationService, new CustomJDBCDaoImpl(), authenticationManager()), UsernamePasswordAuthenticationFilter.class)

                // custom Token based authentication based on the header previously given to the client
                .addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(new CustomJDBCDaoImpl()).passwordEncoder(new BCryptPasswordEncoder());
    }


}

无状态登录过滤器

class StatelessLoginFilter extends AbstractAuthenticationProcessingFilter {

    private final TokenAuthenticationService tokenAuthenticationService;
    private final CustomJDBCDaoImpl userDetailsService;

    protected StatelessLoginFilter(String urlMapping, TokenAuthenticationService tokenAuthenticationService,
            CustomJDBCDaoImpl userDetailsService, AuthenticationManager authManager) {
        super(new AntPathRequestMatcher(urlMapping));
        this.userDetailsService = userDetailsService;
        this.tokenAuthenticationService = tokenAuthenticationService;
        setAuthenticationManager(authManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {

                final UsernamePasswordAuthenticationToken loginToken = new UsernamePasswordAuthenticationToken(
                request.getParameter("username").toString(), request.getParameter("password").toString());
        return getAuthenticationManager().authenticate(loginToken);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
            FilterChain chain, Authentication authentication) throws IOException, ServletException {

        // Lookup the complete User object from the database and create an Authentication for it
        final UserDetails authenticatedUser = userDetailsService.loadUserByUsername(authentication.getName());
        final UserAuthentication userAuthentication = new UserAuthentication(authenticatedUser);

        // Add the custom token as HTTP header to the response
        tokenAuthenticationService.addAuthentication(response, userAuthentication);

        // Add the authentication to the Security context
        SecurityContextHolder.getContext().setAuthentication(userAuthentication);
    }
}

Source Code for Token Authentication Service

Source Code for Token Handler

此外,它直接将我重定向到服务,而不是向我显示输入用户名和密码的对话框。

2 个答案:

答案 0 :(得分:1)

我有类似的设置。 不同的是,我有一个额外的ContextLoaderListener来加载SpringSecurityFilerChain

@WebListener
public class SpringContextLoader extends ContextLoaderListener {

    @Override
    protected WebApplicationContext createWebApplicationContext(final ServletContext sc) {
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        applicationContext.register(SpringConfiguration.class);

        sc.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain")).addMappingForUrlPatterns(null, false, "/*");

        Dynamic dynamic = sc.addServlet("dispatcher", new DispatcherServlet(applicationContext));  
        dynamic.addMapping("/");  
        dynamic.setLoadOnStartup(1); 

        return applicationContext;
    }
}

答案 1 :(得分:0)

如果您有此文件,是否可以尝试在Spring.xml或ApplicationContext.xml文件中配置组件扫描包。你也可以发布错误的堆栈跟踪。

您可能还需要在spring-security.xml中配置filterChainProxy元素并将其绑定到url模式,如/ **