如何使用 Spring Security + Angular 登录/验证
Posted
技术标签:
【中文标题】如何使用 Spring Security + Angular 登录/验证【英文标题】:How to login/authenticate with Spring Security + Angular 【发布时间】:2020-11-17 06:40:47 【问题描述】:我正在尝试使用 Spring boot 2.3.1 + spring security + angular 7 来做一个 webapp。 现在,我的主要目标是如果用户想要登录(使用自定义角度登录页面),前端将数据(用户名和密码)发送到后端,我想在那里进行身份验证并将消息发送回前端(比如: OK 消息什么的)
我的项目是这样工作的: 使用 maven,我构建了 angular 前端,并从“dist”文件夹复制文件/文件夹并放入后端资源文件夹。有了这个解决方案,一切正常,现在我想添加 spring 安全部分。
SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception
auth.inMemoryAuthentication()
.withUser("user1").password("nooppassword123").roles("USER");
@Override
protected void configure(final HttpSecurity http) throws Exception
http
.csrf().disable()
.authorizeRequests()
//.antMatchers(HttpMethod.POST, "/auth").permitAll() // I tried this but nothing
.antMatchers(HttpMethod.GET, "/login", "/index*", "/static/**", "/*.js", "/*.json", "/*.ico", "/*.sccs", "/*.woff2", "/*.css").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/auth")
.usernameParameter("username")
.passwordParameter("password")
.failureUrl("/index.html?error=true")
.permitAll();
ApiController.java
@RestController
public class ApiController
@PostMapping("/auth")
public boolean login(@RequestBody User user)
return user.getUserName().equals("user") && user.getPassword().equals("password"); // I would like to authenticate with auth.inMemoryAuthentication()
我有一个带有 2 个变量(用户名和密码)的 User.java
login.components.ts
import Component, OnInit from '@angular/core';
import Router from '@angular/router';
import FormGroup from '@angular/forms';
import LoggerService from '@app/core/services/logger.service';
import Http from "@angular/http";
import FormControlHelper, Globals from '@app/core/helpers/index';
import loginValidation from '@app/models/form-validations/index';
import HttpParams, HttpHeaders from "@angular/common/http";
import URLSearchParams from "@angular/http"
import MatSnackBar from '@angular/material/snack-bar';
@Component(
selector: 'app-login',
templateUrl: './login.component.html',
)
export class LoginComponent implements OnInit
// Properties
globals: Globals;
public loginForm: FormGroup;
public loginValidationModel: any;
public waiting: boolean;
public hidePassword: boolean;
public params = new HttpParams();
constructor(
globals: Globals,
private router: Router,
private logger: LoggerService,
public http : Http,
private snackBar: MatSnackBar
)
this.loginValidationModel = loginValidation;
this.hidePassword = true;
this.globals = globals;
openSnackBar(message: string, action: string)
this.snackBar.open(message, action,
duration: 5000,
verticalPosition: 'top', // 'top' | 'bottom'
horizontalPosition: 'center', //'start' | 'center' | 'end' | 'left' | 'right'
panelClass: ['red-snackbar'],
);
ngOnInit()
const formGroupObj = FormControlHelper.generateFormControls(this.loginValidationModel);
if (formGroupObj)
this.loginForm = new FormGroup(formGroupObj);
else
this.logger.error(new Error('Error generating the form modal & validations'));
public onSubmit()
let urlSearchParams = new URLSearchParams();
urlSearchParams.append('username', this.loginForm.value.username );
urlSearchParams.append('password', this.loginForm.value.password );
console.log("urlSearchParams: " + urlSearchParams);
this.http.post("auth", urlSearchParams)
.subscribe(
response =>
if(response) //Here I always get code 200 with "OK" status, even if the username/password is bad, I don't know how to fix this part
this.globals.loggeduser=this.loginForm.value.username;
this.router.navigateByUrl('/somewhere');
else
alert("Authentication failed");
);
我试过这个https://spring.io/guides/tutorials/spring-security-and-angular-js/ 来理解它(通过一些 Baeldung 教程),但我现在有点困惑。有人可以帮助我吗?谢谢你,祝你有美好的一天。
编辑:我构建了一个 .war 文件并使用了 Tomcat。
Edit2:更多细节和一些进展。我展示了 2 个示例,使用 1 个有效和 1 个无效的用户名/密码登录。如果用户名/密码无效,我可以看到我在 url 中得到了这个“?error”部分。我的问题:尽管有错误,但在前端我可以登录并且可以访问所有内容(子页面)。我该如何解决这个问题? (如果登录有效 - >在后端/前端重定向和验证并存储它,所以我不必登录子页面如果登录无效,不要重定向只是留在登录页面上并显示一些错误消息) 我知道我必须重做 login.component 中的“public onSubmit()”方法,但我不知道怎么做。注意:两个响应都有“OK”真和状态 200,我猜这不行
Edit3:我还有 1 个问题:如果我是正确的,使用 loginProcessingUrl 我无法使用控制器处理数据(映射到 /auth)。所以在这种情况下它是没有用的,对吧?
【问题讨论】:
您能否也提及您面临的问题。这将有助于我们理解问题 @SridharPatnaik 我在我的问题中加入了“edit2”,也许现在会更好。 【参考方案1】:我找到了一个可能的解决方案。
我稍微修改了 SecurityConfiguration.java(添加了 succesHandler/failureHandler)
SecurityConfiguration.java
@Override
protected void configure(final HttpSecurity http) throws Exception
http.csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.GET, "/login", "/index*", "/static/**", "/*.js", "/*.json", "/*.ico", "/*.sccs","/*.woff2", "/*.css").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/auth")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(successHandler())
.failureHandler(failureHandler())
.permitAll()
.and()
.logout().permitAll();
private AuthenticationSuccessHandler successHandler()
return new AuthenticationSuccessHandler()
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Authentication authentication)
throws IOException, ServletException
httpServletResponse.getWriter().append("OK");
httpServletResponse.setStatus(200);
;
private AuthenticationFailureHandler failureHandler()
return new AuthenticationFailureHandler()
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, AuthenticationException e)
throws IOException, ServletException
httpServletResponse.getWriter().append("Authentication failure");
httpServletResponse.setStatus(401);
;
之后我也更改了前端登录组件。
let urlSearchParams = new URLSearchParams();
urlSearchParams.append('username', this.loginForm.value.username );
urlSearchParams.append('password', this.loginForm.value.password );
if(this.loginForm.value.username != null && this.loginForm.value.password != null)
this.http.post("auth", urlSearchParams).subscribe(
response =>
if(response.status == 200 && response.ok == true)
this.globals.loggeduser=this.loginForm.value.username;
this.router.navigateByUrl('/somewhere');
else
this.openSnackBar("Wrong username or password!","");
);
在这些更改之后,一切正常。
【讨论】:
以上是关于如何使用 Spring Security + Angular 登录/验证的主要内容,如果未能解决你的问题,请参考以下文章
spring security 配置了httpBasic()为啥没有弹框
Spring Security Filter 测试,身份验证在 POSTMAN 中不起作用
Spring security:Spring security 如何在 SessionRegistry 中注册新会话?
如何使用 Spring Security 模拟身份验证和授权
如何使用 Spring-Security 3 和 Hibernate 4 将 spring security xml 配置 hibernate 转换为 java config