如何将凭据从 Angular 前端传递到 Spring 后端(Spring Security 的基本身份验证)
Posted
技术标签:
【中文标题】如何将凭据从 Angular 前端传递到 Spring 后端(Spring Security 的基本身份验证)【英文标题】:How to pass credentials from Angular2 frontend to Spring backend (Basic-Authentification with Spring Security) 【发布时间】:2017-08-03 04:40:52 【问题描述】:我正在开发一个使用 spring 作为后端和 angular2 作为前端的应用程序,后端是安全的(使用 Spring security),当我运行它时,我有默认的登录表单。我想从客户端登录到服务器端,但是当我尝试传递凭据时,我在浏览器控制台中出现了这些错误。
以下是错误:
我正在 Wildfly 服务器(与后端部分相同的端口)上部署我的 angular2 应用程序。
配置类
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = "tn.com.kmf.springdemo.config" )
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private RESTAuthenticationFailureHandler authenticationFailureHandler;
@Autowired
private RESTAuthenticationSuccessHandler authenticationSuccessHandler;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN", "USER").and().withUser("user")
.password("user").roles("USER");
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable()
.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class)
.authorizeRequests()
.antMatchers("/etudiant/list").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/login")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(authenticationSuccessHandler)
.failureHandler(authenticationFailureHandler)
.permitAll()
.and()
.httpBasic();
CorsFilter:
public class CORSFilter implements Filter
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod()))
response.setStatus(HttpServletResponse.SC_OK);
else
chain.doFilter(req, res);
@Override
public void init(FilterConfig filterConfig)
@Override
public void destroy()
web.xml 中的安全过滤器:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
angular2侧的登录表单:
<div class="login jumbotron center-block">
<h1>Login</h1>
<form role="form" (submit)="login(username.value, password.value)">
<div class="form-group">
<label for="username">Username</label>
<input type="text" #username class="form-control" id="username" placeholder="Username">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" #password class="form-control" id="password" placeholder="Password">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
服务代码:(login.service.ts)
import Injectable from '@angular/core';
import Http, Response, Headers from '@angular/http';
import Observable from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
@Injectable()
export class LoginService
isAuthenticated = false;
constructor(private http: Http)
login(username: string, password: string)
const headers = new Headers();
const creds = 'username=' + username + '&password=' + password;
// headers.append('Content-Type', 'application/json');
headers.append('Authorization', 'Basic ' +
btoa(username+':'+password));
headers.append('Content-Type', 'application/x-www-form-urlencoded');
return new Promise((resolve) =>
this.http.post('http://localhost:8080/StudentManager/login', creds, headers: headers ).subscribe((data) =>
console.log(creds);
if (data.json().success)
// window.localStorage.setItem('auth_key', data.json().token);
// this.userId = data.json().userId;
this.isAuthenticated = true;
resolve(this.isAuthenticated);
);
);
【问题讨论】:
如果你想使用表单登录,你必须发送内容类型为application/x-www-form-urlencoded
而不是JSON的用户名和密码。
我把它改成了 application/x-www-form-urlencoded 但我仍然有同样的错误
不,我只是发送没有 JSON.stringify 的凭据
我重建它,现在我认为它可以工作,因为我有状态代码:200 ok,但为什么我有这个错误EXCEPTION: Unexpected end of JSON input
以及如何修复它?谢谢你对我这么有耐心
响应正文中没有html
【参考方案1】:
当你声明这个时:
.and().formLogin()
默认登录端点应该是:" yourAppContextPath/login?user=myUser&password=myPassword " ;
当你声明时:
.and().httpBasic();
表示你要使用spring“基本访问认证”
所以登录后你应该每次都发送一个值为“Basic :”的标题
var authenticate = function(credentials, callback)
var headers = credentials ?
authorization : "Basic "
+ btoa(credentials.username + ":"
+ credentials.password)
: ;
$http.get('user',
headers : headers
).then(function(response)
if (response.data.name)
$rootScope.authenticated = true;
else
$rootScope.authenticated = false;
callback && callback($rootScope.authenticated);
, function()
$rootScope.authenticated = false;
callback && callback(false);
);
有完整的示例可能对您有所帮助: https://github.com/spring-guides/tut-spring-security-and-angular-js/blob/master/single/src/main/resources/static/js/hello.js
您也在使用 CORS!所以你必须在你的登录页面中添加一个 _cors 令牌。
【讨论】:
以上是关于如何将凭据从 Angular 前端传递到 Spring 后端(Spring Security 的基本身份验证)的主要内容,如果未能解决你的问题,请参考以下文章
如何将数据从 AngularJS 前端传递到 Nodejs 后端?
将错误消息从 SSE (Webflux) Spring Boot 应用程序传递到 Angular 7 前端
如何使用 JWT 从前端(角度 4)将密钥传递到后端(节点 js)