如何将包含 CSRF 令牌的数据从 angularjs 控制器提交到 REST 控制器?
Posted
技术标签:
【中文标题】如何将包含 CSRF 令牌的数据从 angularjs 控制器提交到 REST 控制器?【英文标题】:How to submit data including the CSRF token from angularjs controller to REST controller? 【发布时间】:2018-11-04 09:46:37 【问题描述】:我正在尝试使用从角度控制器到 REST 控制器的模式提交数据。 PUT,GET,POST 方法工作代码仅在 CSRF 被disbaled 时起作用,但当我 启用 CSRF 时 PUT 和 POST 不起作用。我检查了控制台日志,上面写着 405 (Method Not Allowed)。
我知道我需要将数据与 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()
我的 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">
我在 Angular 控制器上的代码是超级新手,所以任何建议都非常感谢:)。
【问题讨论】:
真的为什么要投反对票? 【参考方案1】:你可以通过你喜欢的 jQuery 或纯 javascript 来获得那个 csrf-token。然后您应该将该令牌附加到您的资源标头中。
【讨论】:
感谢劳伦斯的回答,但我更喜欢使用角度控制器而不是 jquery 或纯 javascript。我已经这样做了,现在我正在尝试将代码转换为角度。 好的,请注意任何 DOM 操作都应该在指令中完成,并且尽可能不要在控制器中进行。根据角度最佳实践。 这个链接解决了我的问题。 spring.io/blog/2015/01/12/… .Angular 内置了对基于 cookie 的 CSRF(它称为“XSRF”)的支持。【参考方案2】:注意:我是 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
【讨论】:
以上是关于如何将包含 CSRF 令牌的数据从 angularjs 控制器提交到 REST 控制器?的主要内容,如果未能解决你的问题,请参考以下文章
使用 CSRF_COOKIE_HTTPONLY 将 Django CSRF 令牌传递给 Angular