如何将包含CSRF令牌的数据从angularjs控制器提交到REST控制器?

时间:2018-05-25 04:38:22

标签: angular spring-security csrf

我正在尝试使用从角度控制器到REST控制器的模态提交数据。 PUT,GET,POST 方法工作代码仅在CSRF 消除时有效,但当我启用 CSRF时,PUT和POST无法正常工作。我检查了控制台日志,并说它是 405(方法不允许)

我知道我需要将数据与 csrf令牌 一起传递,但我无法弄清楚在使用角度控制器传递数据时如何包含它。这是我的第一个角度。任何建议都非常感谢。所以这是我的代码。

我的配置:

public class CORSFilter implements Filter {

    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);
    }

    public void init(FilterConfig filterConfig) {}

    public void destroy() {}

}

My SecurityConfiguration.java

Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("customUserDetailsService")
    UserDetailsService userDetailsService;

    @Autowired
    PersistentTokenRepository tokenRepository;

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.userDetailsService(userDetailsService);
        auth.authenticationProvider(authenticationProvider());
    }

    /* This method sets-up the list of accessing page for each role. */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // Request Mapping accessible
                .antMatchers("/restUser/**") // -------> HERE I INCLUDE THE REQUEST MAPPING
                // Roles
                .access("hasRole('ADMIN')").and().formLogin()
                .loginPage("/login").loginProcessingUrl("/login")
                .usernameParameter("usernameId").passwordParameter("password").and()
                .rememberMe().rememberMeParameter("remember-me")
                .tokenRepository(tokenRepository).tokenValiditySeconds(86400)
                .and().csrf().and().exceptionHandling()
                .accessDeniedPage("/Access_Denied");

        // Disable spring security
        // http.csrf().disable(); 

    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    }

    @Bean
    public PersistentTokenBasedRememberMeServices getPersistentTokenBasedRememberMeServices() {
        PersistentTokenBasedRememberMeServices tokenBasedservice = new PersistentTokenBasedRememberMeServices(
                "remember-me", userDetailsService, tokenRepository);
        return tokenBasedservice;
    }

    @Bean
    public AuthenticationTrustResolver getAuthenticationTrustResolver() {
        return new AuthenticationTrustResolverImpl();
    }

}

我的RestController:

@RestController
public class UserRestController {

    @Autowired
    UserService userService;

    // -------------------Retrieve All
    // Users--------------------------------------------------------

    @RequestMapping(value = "/restUser", method = RequestMethod.GET)
    public ResponseEntity<List<User>> listAllUsers() {
        List<User> users = userService.findAllUsers();
        if (users.isEmpty()) {
            return new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT);
        }
        return new ResponseEntity<List<User>>(users, HttpStatus.OK);

    }

    // -------------------Create a
    // User--------------------------------------------------------

    @RequestMapping(value = "/restUser", method = RequestMethod.POST)
    public ResponseEntity<Void> createUser(@RequestBody User user,
            UriComponentsBuilder ucBuilder) {
        System.out.println("Creating User " + user.getUsernameId());

        // if (userService.isUserExist(user)) {
        // System.out.println("A User with name " + user.getUsername() +
        // " already exist");
        // return new ResponseEntity<Void>(HttpStatus.CONFLICT);
        // }

        userService.saveUser(user);
        System.out.println("Fetch Data: " + user);
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(ucBuilder.path("/restUser/{id}")
                .buildAndExpand(user.getId()).toUri());
        return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
    }

    // -------------------Retrieve Single
    // User--------------------------------------------------------

    @RequestMapping(value = "/restUser/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<User> getUser(@PathVariable("id") int id) {
        System.out.println("Fetching User with id " + id);
        User user = userService.findById(id);
        if (user == null) {
            System.out.println("User with id " + id + " not found");
            return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
        }

        System.out.println("Fetch Data: " + user);
        return new ResponseEntity<User>(user, HttpStatus.OK);
    }

    // ------------------- Update a User
    // --------------------------------------------------------

    @RequestMapping(value = "/restUser/{id}", method = RequestMethod.PUT)
    public ResponseEntity<User> updateUser(@PathVariable("id") int id,
            @RequestBody User user) {
        System.out.println("Updating User " + id);

        User currentUser = userService.findById(id);
        //
        // if (currentUser==null) {
        // System.out.println("User with id " + id + " not found");
        // return new ResponseEntity<User>(HttpStatus.NOT_FOUND);
        // }

        // currentUser.setUsernameId(user.getUsernameId());
        // currentUser.setFirstName(user.getFirstName());
        // currentUser.setEmail(user.getEmail());

        System.out.println("USER: " + user);
        userService.updateUser(user);
        return new ResponseEntity<User>(currentUser, HttpStatus.OK);
    }

}

App.js

'user strict';

var App = angular.module('myApp', ['ngResource', 'ngAnimate', 'ui.bootstrap']);

user_service.js

'use strict';


App.factory('User', ['$resource', function ($resource) {
    //$resource() function returns an object of resource class
    return $resource(
            'http://localhost:8080/MavenTry/restUser/:id', 
            {id: '@id'},//Handy for update & delete. id will be set with id of instance
            {
                update: {
                      method: 'PUT' // To send the HTTP Put request when calling this custom update method.
                }

            }
    );
}]);

user_controller.js

'use strict';

App
        .controller(
                'UserController',
                [
                        '$scope',
                        'User',
                        '$uibModal',
                        '$log',
                        function($scope, User, $uibModal, $log) {
                            var self = this;
                            self.user = new User();

                            self.users = [];

                            //Fetch all user data
                            self.fetchAllUsers = function() {
                                self.users = User.query();
                                $log.info('self.users: ', self.users);
                            };

                            // Call function fetchAllUsers                          
                            self.fetchAllUsers();


                            $scope.open = function(id) {

                                $log.info("parameter id: " + id);
                                $scope.items = [];

                                for (var i = 0; i < self.users.length; i++) {
                                    if (self.users[i].id === id) {
                                        self.user = angular.copy(self.users[i]);
                                        $scope.items = angular
                                                .copy(self.users[i]);
                                        break;

                                    }
                                }

                                var modalInstance = $uibModal.open({
                                    templateUrl : 'myModal1',
                                    controller : 'ModalInstance',
                                    size : 'lg',
                                    resolve : {
                                        items : function() {
                                            return $scope.items;
                                        }
                                    }
                                });
                            };

                                self.reset = function() {
                                self.user = new User();
                                $scope.myForm.$setPristine(); // reset Form
                            };

                        } ]);


// Populate modal with data
App.controller('ModalInstance', function($scope, $uibModalInstance, items,
        $log, User) {

    $scope.form = {};
    var myModal = this;
    myModal.user = new User();

    myModal.users = [];

    myModal.fetchAllUsers = function() {
        myModal.users = User.query();
    };

    // Populate DataTable using $GET
    myModal.fetchAllUsers = function() {
        myModal.users = User.query();
        };

    // Create user using $POST
    myModal.createUser = function() {
        myModal.user.$save(function() {
        myModal.fetchAllUsers();
        });
    };

    // Update $PUT
    myModal.updateUser = function() {
            myModal.user.$update(function() {
            myModal.fetchAllUsers();
        });
    };


    $scope.userInfo = items;

    $scope.submitForm = function() {
        if ($scope.form.userForm.$valid) {
            console.log('CSRF_TOKEN', csrftoken); // Here i retrieve the token from the view page. Dont know how to include this while submiting data
            myModal.user = $scope.userInfo;

            // Call function for PUT
            myModal.updateUser();

            $uibModalInstance.close('closed');
        } else {
            console.log('userform is not in scope');
        }

    };

    $scope.cancel = function() {
        $uibModalInstance.dismiss('cancel');
    };
});


//Retrieving CSRF_TOKEN
var csrftoken = (function() {
    var metas = window.document.getElementsByTagName('meta');

    // finding one has csrf token
    for (var i = 0; i < metas.length; i++) {
        if (metas[i].name === "csrf-token") {
            return metas[i].content;
        }
    }

})();

App.constant('CSRF_TOKEN', csrftoken);

在我看来,jsp我将csrf标记存储在

<meta name="csrf-token" content="${_csrf.token}">

我在角度控制器的代码是超级新手所以任何建议都非常感激:)。

2 个答案:

答案 0 :(得分:0)

你可以获得那个你更喜欢jQuery或普通javascript的csrf-token。然后,您应该将该标记附加到资源标题中。

答案 1 :(得分:0)

注意:我是OP,这个答案实际上解决了这个问题。

解决方法需要将以下行添加到SecurityConfiguration类:

/* This method sets-up the list of accessing page for each role. */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // Request Mapping accessible
                .antMatchers("/restUser/**") // -------> HERE I INCLUDE THE REQUEST MAPPING
                // Roles
                .access("hasRole('ADMIN')").and().formLogin()
                .loginPage("/login").loginProcessingUrl("/login")
                .usernameParameter("usernameId").passwordParameter("password").and()
                .rememberMe().rememberMeParameter("remember-me")
                .tokenRepository(tokenRepository).tokenValiditySeconds(86400)
                .and().csrf().and().exceptionHandling()
                .accessDeniedPage("/Access_Denied").and()
              .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class).csrf().csrfTokenRepository(csrfTokenRepository());

    }    

private CsrfTokenRepository csrfTokenRepository() {
          HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
          repository.setHeaderName("X-XSRF-TOKEN");
          return repository;
        }

创建一个CsrfHeaderFilter.class

public class CsrfHeaderFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
                .getName());
        if (csrf != null) {
            Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
            String token = csrf.getToken();
            if (cookie == null || token != null
                    && !token.equals(cookie.getValue())) {
                cookie = new Cookie("XSRF-TOKEN", token);
                cookie.setPath("/");
                response.addCookie(cookie);
            }
        }
        filterChain.doFilter(request, response);

    }
}

添加 .addFilterAfter(new CsrfHeaderFilter(),CsrfFilter.class).csrf()。csrfTokenRepository(csrfTokenRepository()

现在POST和PUT方法有效。我知道我的代码不是很干净,需要修改才能遵循最佳实践。

参考:https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii