0

i try to make a simple login and registration page. Fronted is make by Angular a backend in Spring framework. User data are save in MYSQL DB. My problem is that I don't know how to check my credentials in backend with database. After successful login I would like to redirect to / welcome page and unsuccessful print error message. Also, I don't know if the login endpoint is correct. Call / basicauth in angular or / login in form?

I also have a registration page that works and stores new users in the database.

My error console.log

Access to XMLHttpRequest at 'http://localhost:8080/basicauth' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request. login.component.ts:33 HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: "http://localhost:8080/basicauth", ok: false, …} zone-evergreen.js:2952 GET http://localhost:8080/basicauth net::ERR_FAILED

User.java

@Entity
@Table(name = "user")
public class User{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;

@Column(name="name")
private String name;

@Column(name="password")
private String password;

@Column(name="role")
private String role;

@Column(name="status")
private boolean status;

public User() {
}

public User(String name, String password) {
    this.name = name;
    this.password = password;
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

public String getRole() {
    return role;
}

public void setRole(String role) {
    this.role = role;
}

public boolean getStatus() {
    return status;
}

public void setStatus(boolean status) {
    this.status = status;
}
}

UserController

@CrossOrigin(origins="http://localhost:4200")
@RestController
public class UserController {

@Autowired
private UserService userService;

@GetMapping(path="/basicauth")
public AuthenticationBean helloWorldBean(){
    //throw new RuntimeException("Some Error");
    return new AuthenticationBean("You are authenticated");
}

@PostMapping("/registration")
public User create(@RequestBody Map<String, String> body){
    String username = body.get("username");
    String password = body.get("password");
    return userService.saveUser(new User(username, password));
}
}

MyUserDetailsService

@Service
public class MyUserDetailsService implements UserDetailsService {

@Autowired
private UserService userService;

@Override
@Transactional
public UserDetails loadUserByUsername(String userName) {
    User user = userService.findUserByName(userName);
    List<GrantedAuthority> authorities = getUserAuthority(user.getRole());
    return buildUserForAuthentication(user, authorities);
}

private List<GrantedAuthority> getUserAuthority(String userRoles) {
    Set<GrantedAuthority> roles = new HashSet<>();

    roles.add(new SimpleGrantedAuthority(userRoles));

    return new ArrayList<>(roles);
}

private UserDetails buildUserForAuthentication(User user, List<GrantedAuthority> authorities) {
    return new org.springframework.security.core.userdetails.User(user.getName(), user.getPassword(),
            user.getStatus(), true, true, true, authorities);
}
}

UserService

@Service
public class UserService {

private UserRepository userRepository;
private BCryptPasswordEncoder bCryptPasswordEncoder;

@Autowired
public UserService(UserRepository userRepository,
                   BCryptPasswordEncoder bCryptPasswordEncoder) {
    this.userRepository = userRepository;
    this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}


public User findUserByName(String userName) {
    return userRepository.findByName(userName);
}

public User saveUser(User user) {
    user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
    user.setName(user.getName());
    user.setStatus(true);
    user.setRole("USER");
    return userRepository.save(user);
}

}

Webconfig

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;

@Autowired
private MyUserDetailsService userDetailsService;



@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(bCryptPasswordEncoder);
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    String loginPage = "/login";
    String logoutPage = "/logout";

    http.
            authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers(loginPage).permitAll()
            .antMatchers("/registration").permitAll()
            .antMatchers("/admin/**").hasAuthority("ADMIN")
            .anyRequest()
            .authenticated()
            .and().csrf().disable()
            .formLogin()
            .loginPage(loginPage)
            .loginPage("/")
            .failureUrl("/login?error=true")
            .defaultSuccessUrl("/welcome")
            .usernameParameter("username")
            .passwordParameter("password")
            .and().logout()
            .logoutRequestMatcher(new AntPathRequestMatcher(logoutPage))
            .logoutSuccessUrl(loginPage).and().exceptionHandling();
}

@Override
public void configure(WebSecurity web) throws Exception {
    web
            .ignoring()
            .antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**");
}

}

HttpIntercepterBasicAuthService.ts

    export class HttpIntercepterBasicAuthService {

    constructor(
    private basicAuthenticationService: BasicAuthenticationService
  ) { }

  intercept(request: HttpRequest<any>, next: HttpHandler){

    const basicAuthHeaderString = this.basicAuthenticationService.getAuthenticatedToken();
    const username = this.basicAuthenticationService.getAuthenticatedUser()

    if (basicAuthHeaderString && username) {
      request = request.clone({
        setHeaders : {
          Authorization : basicAuthHeaderString
        }
      });
    }
    return next.handle(request);
    }
    }

BasicAuthenticationService.ts

    export const TOKEN = 'token';
    export const AUTHENTICATEDUSER = 'authenticaterUser';

    @Injectable({
     providedIn: 'root'
    })

  export class BasicAuthenticationService {

  constructor(private http: HttpClient) { }

  executeAuthenticationService(username, password) {

    const basicAuthHeaderString = 'Basic ' + window.btoa(username + ':' + password);
    const headers = new HttpHeaders(
      {Authorization: basicAuthHeaderString}
    )
    return this.http.get<AuthenticationBean>(`${API_URL}/basicauth`,
      {headers}).pipe(
      map(data => {
        sessionStorage.setItem(AUTHENTICATEDUSER, username);
        sessionStorage.setItem(TOKEN, basicAuthHeaderString);
        return data;
      })
    );

  }

  getAuthenticatedUser() {
    return sessionStorage.getItem(AUTHENTICATEDUSER);
  }

  getAuthenticatedToken() {
    if (this.getAuthenticatedUser()) {
      return sessionStorage.getItem(TOKEN);
    }
  }

  logout() {
    sessionStorage.removeItem(AUTHENTICATEDUSER);
    sessionStorage.removeItem(TOKEN);
  }

  isLoggedIn() {
    const user = sessionStorage.getItem(AUTHENTICATEDUSER);
    return !(user === null);
  }
}

export class AuthenticationBean{
  constructor(public message: string) { }
}

LoginComponent.ts

export class LoginComponent implements OnInit {

  username = '';
  password = '';
  errorMessage = 'Špatné přihlašovací údaje';
  invalidLogin = false;
  // router

  constructor(private router: Router,
              private basicAuthenticationService: BasicAuthenticationService) { }

  ngOnInit() {
  }

  handleLogin() {
    this.basicAuthenticationService.executeAuthenticationService(this.username, this.password)
      .subscribe(
        data => {
          console.log(data);
          this.router.navigate(['welcome']);
          this.invalidLogin = false;
        },
        error => {
          console.log(error);
          this.invalidLogin = true;
        }
      );
    // redirect welcome page
  }

}

1 Answers1

0

You have a problem with redirection of request from Angular application to your backend server because your frontend app tries to access backend from a different domain. To fix this problem please use the angular proxy: https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/proxy.md

  • I should send GET or POST (with username and password) request from angular to backend? – user3699313 Feb 26 '20 at 12:47
  • When you Registering and Login you should request server with method POST from security reason https://www.w3schools.com/tags/ref_httpmethods.asp – Łukasz Ozimek Feb 26 '20 at 12:52
  • proxy not help me. The problem is somewhere else. With the correct credentials, I log in without error. But with bad credentials comes the problem. How to handle the situation on the backend? How do I send back a notification that my login information is incorrect? – user3699313 Feb 26 '20 at 14:17
  • Hmm, You have to provide more information about what is logged and what kind of error you have? Did the redirection(CORS) problem disappear? – Łukasz Ozimek Feb 26 '20 at 14:56
  • `Access to XMLHttpRequest at 'http://localhost:8080/basicauth' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. login.component.ts:33 HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: "http://localhost:8080/basicauth", ok: false, …} zone-evergreen.js:2952 GET http://localhost:8080/basicauth net::ERR_FAILED` – user3699313 Feb 26 '20 at 15:03
  • Also i change WebSecurity in Spring security: ` http.csrf().disable(). authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll() .anyRequest().authenticated() .and().httpBasic();` – user3699313 Feb 26 '20 at 15:04
  • Ok provide me proxy configuration – Łukasz Ozimek Feb 26 '20 at 15:04
  • `{ "/": { "target": "http://localhost:8080", "secure": false } }` – user3699313 Feb 26 '20 at 15:07
  • Could you put the code to the repository and share it so I can pull and verify it? – Łukasz Ozimek Feb 27 '20 at 07:38
  • probably the error is in spring config websecurity. Also, I don't know how to handle bad login information. https://bitbucket.org/dkolec/springlogin – user3699313 Feb 27 '20 at 10:24
  • I think yes I reviewed the code and I see the problem that you try to connect with spring configuration and what you want to try achive look: https://www.baeldung.com/spring-security-basic-authentication this is article which allow you to find how to build the Authentication type BASIC. https://stackoverflow.com/questions/3044315/how-to-set-the-authorization-header-using-curl – Łukasz Ozimek Feb 27 '20 at 10:40
  • So what I am thinking the problem is in the fact that you send a wrong header and spring try to return you BasicAuth form and right now you have got conflict because you are working on frontend on port 4200 and server 8080. So if you want to do something like this just pack the angular app to your Spring app – Łukasz Ozimek Feb 27 '20 at 10:44