如何使用Angular + Spring + JSON自定义登录/认证。

huangapple go评论71阅读模式
英文:

How to custom Login / authenticate with Angular + Spring + JSON

问题

你的目标是在Angular 7前端和Spring后端中实现自定义JSON表单登录。计划是将用户名/密码从前端以JSON形式发送到后端,然后在后端进行身份验证,将结果返回到前端。问题是,在从前端发送数据后,在后端无法看到数据(用户名和密码为空)。

你的登录页面功能中,credential 的设置看起来正确。但是请注意,你在比较用户名和密码是否为 null 时使用了 &&,这应该是 &&

关于后端部分,在 CustomAuthenticationProvider.java 中,你尝试获取用户名和密码,但遇到了问题,它们为空。首先,请确保前端发送的数据是有效的 JSON 格式。另外,你可能需要查看前端是否正确设置了请求的 Content-Type 为 application/json

CustomAuthenticationProvider 中,你的问题可能出在身份验证之前,需要在请求中正确获取 JSON 数据。你可以尝试以下方式来获取用户名和密码:

import com.fasterxml.jackson.databind.ObjectMapper;

// ...

@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
    ObjectMapper objectMapper = new ObjectMapper();
    Map<String, String> data = objectMapper.convertValue(authentication.getDetails(), Map.class);

    final String username = data.get("username");
    final String password = data.get("password");

    // 确保你可以正确获取到用户名和密码后,进行身份验证
}

这应该可以帮助你在后端获取到从前端发送的 JSON 数据中的用户名和密码,从而进行身份验证。如果问题仍然存在,请确保前端和后端的数据传输格式和请求设置正确。

英文:

I have an angular 7 frontend and Spring backend.

My goal is to make a custom login using JSON form. The plan: send the username/password from frontend to backend in json form. Do the authentication in backend, and send back the result to frontend. My problem: after sending the data from frontend, I can't see the data in backend (username and password are empty) (in my CustomAuthenticationProvider.java)

My login page function:

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

if(this.loginForm.value.username != null &amp;&amp; this.loginForm.value.password != null) {
     this.http.post(&quot;auth&quot;, JSON.stringify(credential)).subscribe(
           response =&gt; {
                if(response.status == 200 &amp;&amp; response.ok == true) {
                   this.globals.loggeduser = this.loginForm.value.username;
                   //and routing
                } else {
                     alert(&quot;Bad credential&quot;);
           } 
     );
}
@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&lt;GrantedAuthority&gt; grantedAuths = new ArrayList&lt;&gt;();
                grantedAuths.add(new SimpleGrantedAuthority(&quot;ROLE_USER&quot;));
                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&lt;?&gt; 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,&quot;/login&quot;, &quot;/index*&quot;, &quot;/static/**&quot;, &quot;/*.js&quot;, 
                                        &quot;/*.json&quot;, &quot;/*.ico&quot;, &quot;/*.sccs&quot;, &quot;/*.woff2&quot;, &quot;/*.css&quot;).permitAll()
            .anyRequest()
                .authenticated()
                .and()
            .formLogin()
                .loginPage(&quot;/&quot;)
                .loginProcessingUrl(&quot;/auth&quot;)
                .usernameParameter(&quot;username&quot;)
                .passwordParameter(&quot;password&quot;)
                .successHandler(successHandler())
                .failureHandler(failureHandler())
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    private AuthenticationSuccessHandler successHandler() {
       ...
    }

    private AuthenticationFailureHandler failureHandler() {
       ...
    }
}

When I print out the authentication after adding values to username and password, I get this (Principal and credentials are empty):

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

Using not JSON format works fine, but I need to use JSON format. I read this and this (I tried these solutions, didn't work). These are a bit outdated and not good (too complex and/or in xml format)
I read about that I have to write a custom UsernamePasswordAuthenticationFilter / using Beans, but I would like to do a nice and clean java solution without reworking the whole thing / using xml. Can I get some help/hints please?

Edit: using this format (instead of let credential = ... ), it is working (but it is not JSON unfortunately):

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

答案1

得分: 0

我找到了一个解决方案。

我添加了一个CustomAuthenticationFilter,感谢@oe.elvik在这个问题中的回答。
(注意:LoginRequest是一个包含两个变量(username和password)的类)
之后,我将这个内容添加到了我的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;
}
英文:

I found a solution.

I added a CustomAuthenticationFilter, credits go to @oe.elvik's answer in this question.
(note: LoginRequest is a class with 2 variables: username and password)
After that, I added this into my securityConfig, and everything is working:

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

    return customAuthenticationFilter;
}

huangapple
  • 本文由 发表于 2020年8月3日 21:53:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/63230768.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定