如何使用 Angular + Spring + JSON 自定义登录/身份验证

Posted

技术标签:

【中文标题】如何使用 Angular + Spring + JSON 自定义登录/身份验证【英文标题】:How to custom Login / authenticate with Angular + Spring + JSON 【发布时间】:2020-11-23 14:22:05 【问题描述】:

我有一个 Angular 7 前端和 Spring 后端。

我的目标是使用 JSON 表单进行自定义登录。计划:将用户名/密码以 json 形式从前端发送到后端。在后端进行身份验证,并将结果发送回前端。我的问题:从前端发送数据后,我看不到后端的数据(用户名和密码为空)(在我的 CustomAuthenticationProvider.java 中)

我的登录页面功能:

let credential = username: this.loginForm.value.username, password: this.loginForm.value.password;

if(this.loginForm.value.username != null && this.loginForm.value.password != null) 
     this.http.post("auth", JSON.stringify(credential)).subscribe(
           response => 
                if(response.status == 200 && response.ok == true) 
                   this.globals.loggeduser = this.loginForm.value.username;
                   //and routing
                 else 
                     alert("Bad credential");
            
     );

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider 

    public CustomAuthenticationProvider() 
        super();
    

    @Override
    public Authentication authenticate(final Authentication authentication) throws AuthenticationException 
        final String username = authentication.getName();
        final String password = authentication.getCredentials().toString();

 //THE PROBLEM: username and password are empty here

            if (/* some custom auth here */) 
                final List<GrantedAuthority> grantedAuths = new ArrayList<>();
                grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
                final UserDetails principal = new User(username, password, grantedAuths);
                final Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
             
                return auth;
            

        return null;
    

    @Override
    public boolean supports(Class<?> authentication) 
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    


@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter 

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Override
    protected void configure(final AuthenticationManagerBuilder auth) throws Exception 
        auth.authenticationProvider(customAuthenticationProvider);
    

    @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() 
       ...
    

    private AuthenticationFailureHandler failureHandler() 
       ...
    

当我在向用户名和密码添加值后打印出 authentication 时,我得到了这个(主体和凭据为空):

org.springframework.security.authentication.UsernamePasswordAuthenticationToken@b37b: Principal: ; Credentials: [PROTECTED];
Authenticated: false; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364:
RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Not granted any authorities

不使用 JSON 格式可以正常工作,但我需要使用 JSON 格式。我阅读了this 和this(我尝试了这些解决方案,但没有用)。这些有点过时而且不好(太复杂和/或 xml 格式) 我读到我必须编写一个自定义的 UsernamePasswordAuthenticationFilter / 使用 Beans,但我想做一个漂亮而干净的 java 解决方案,而不需要重新处理整个事情 / 使用 xml。请问我可以得到一些帮助/提示吗?

编辑:使用这种格式(而不是let credential = ... ),它可以工作(但不幸的是它不是 JSON):

let urlSearchParams = new URLSearchParams();
urlSearchParams.append('username', this.loginForm.value.username );
urlSearchParams.append('password', this.loginForm.value.password );

【问题讨论】:

【参考方案1】:

我找到了解决办法。

我添加了一个 CustomAuthenticationFilter,学分转到@oe.elvik 在this 问题中的回答。 (注意:LoginRequest 是一个有 2 个变量的类:用户名和密码) 之后,我将其添加到我的 securityConfig 中,一切正常:

@Bean
public CustomAuthenticationFilter customAuthenticationFilter() throws Exception
    CustomAuthenticationFilter customAuthenticationFilter = new CustomAuthenticationFilter();
    customAuthenticationFilter.setAuthenticationManager(authenticationManager());
    customAuthenticationFilter.setFilterProcessesUrl("/auth");
    customAuthenticationFilter.setAuthenticationSuccessHandler(successHandler());
    customAuthenticationFilter.setAuthenticationFailureHandler(failureHandler());

    return customAuthenticationFilter;

【讨论】:

以上是关于如何使用 Angular + Spring + JSON 自定义登录/身份验证的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 keycloak 保护 angular/spring 应用程序?

如何使用 Spring Security + Angular 登录/验证

如何使用 Angular + Spring + JSON 自定义登录/身份验证

如何在 Grails 和 AngularJS 上使用 Spring Security 进行 Ajax 登录

如何使用 Angular 消除 Spring Boot 中的 CORS 错误? [复制]

如何使用spring boot和angular 2登录