java - Angular 与 Spring Boot 后端在获取 JWT 后在现有路线上返回 404

标签 java spring angular jwt

我正在尝试开发一个简单的 Web 应用程序,以 Angular 作为前端,以 Spring Boot 作为后端。我的飞行前请求成功,我收到了一个有效的 token ,但是当尝试向路由发出后续请求时,我得到了 404。当我尝试 curl URL 时,我得到了 500,其中包含消息“缺少或无效的授权 header ”,在我看来,这似乎是说该路由确实存在并且正在监听,但还有其他问题。

首先是 typescript 。这是我的 login.component.ts

import { Component } from "@angular/core";
import { Observable } from "rxjs/index";
import { LoginService } from "../services/login.service";

@Component({
    selector: "login",
    templateUrl: "./login.component.html"
})

export class Login {
    private model = {"username": "", "password": ""};
    private currentUserName;

    constructor (private loginService: LoginService) {
        this.currentUserName = localStorage.getItem("currentUserName");
    }

    public onSubmit() {
        console.log("submitting");
        this.loginService.sendCredential(this.model).subscribe(
            data => {
                console.log(data);
                localStorage.setItem("token", data);
                console.log("Setting token");
                this.loginService.sendToken(localStorage.getItem("token")).subscribe(
                    data => {
                        this.currentUserName = this.model.username;
                        localStorage.setItem("currentUserName", this.model.username);
                        this.model.username = "";
                        this.model.password = "";
                    },
                    error => console.log(error)

                );
            },
            error => {
                console.log("oh no");
                console.log(error)
            }
        );
    }
}

然后是我的LoginService

import { Injectable } from "@angular/core";
import { HttpClient } from '@angular/common/http';
import { HttpHeaders } from '@angular/common/http';
import { Observable } from "rxjs/index";

@Injectable()
export class LoginService {
    token: string;
    constructor (private http: HttpClient) {}

    public sendCredential(model): Observable<String> {
        const tokenUrlPreFlight = "http://localhost:8080/users/login/";
        const httpOptions: {} = {
            headers: new HttpHeaders({
                'ContentType': 'application/json'
            })
        };
        return this.http.post<String>(tokenUrlPreFlight, model, httpOptions);
    }

    public sendToken(token) {
        const tokenUrlPostFlight = "http://localhost:8080/rest/users/";
        console.log("Bearer " + token);

        const httpOptions: {} = {
            headers: new HttpHeaders({
                'Authorization': 'Bearer ' + token
            })
        };

        return this.http.get(tokenUrlPostFlight, httpOptions);
    }

    public logout(): void {
        localStorage.setItem("token", "");
        localStorage.setItem("currentUserName", "");
        alert("You just logged out");
    }

    public checkLogin(): boolean {
        if(localStorage.getItem("currentUserName") != null && localStorage.getItem("currentUserName") != "" && localStorage.getItem("token") != null && localStorage.getItem("token") != "") {
            console.log(localStorage.getItem("currentUserName"));
            console.log(localStorage.getItem("token"));
            return true;
        }

        return false;
    }
}

现在是java。首先这是我的入口点:

import com.acb.app.configuration.JwtFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class App {

    @Bean
    public FilterRegistrationBean jwtFilter() {
        final FilterRegistrationBean<JwtFilter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new JwtFilter());
        filterRegistrationBean.addUrlPatterns("/rest/*");
        return filterRegistrationBean;
    }

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

我的UserController.java

import com.acb.app.model.User;
import io.jsonwebtoken.*;
import com.acb.maki.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("")
    public List<User> userIndex() {
        return userService.getAllUsers();
    }

    @GetMapping("{username}")
    public Optional<User> getUserByUsername(@RequestBody String username) {
        return userService.findByUsername(username);
    }

    @PostMapping("login")
    public String login(@RequestBody Map<String, String> json) throws ServletException {
        if(json.get("username") == null || json.get("password") == null) {
            throw new ServletException("Please fill in username and password");
        }

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

        Optional<User> optionalUser = userService.findByUsername(username);
        if(!optionalUser.isPresent()) {
            throw new ServletException("Username not found");
        }

        User user = optionalUser.get();

        if(!password.equals(user.getPassword())) {
            throw new ServletException("Invalid login. Please check username and password");
        }
        final String response = Jwts.builder().setSubject(username).claim("roles", "user").setIssuedAt(new Date()).signWith(SignatureAlgorithm.HS256, "secretKey").compact();
        final String jsonResponse = String.format("\"%s\"", response);

        System.out.println(jsonResponse);
        return jsonResponse;
    }

    @PostMapping(value="/register")
    public User register(@RequestBody User user) {
        return userService.save(user);
    }
}

最后但并非最不重要的一点是我的JwtFilter.java

import io.jsonwebtoken.*;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;



public class JwtFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        final HttpServletRequest request = (HttpServletRequest) servletRequest;
        final HttpServletResponse response = (HttpServletResponse) servletResponse;
        final String authHeader = request.getHeader("Authorization");
        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                throw new ServletException("Missing or invalid authorization header");
            }

            final String token = authHeader.substring(7);

            try {
                final JwtParser jwtParser = Jwts.parser();
                final Jws<Claims> claimsJws = jwtParser.setSigningKey("secretKey").parseClaimsJws(token);
                final Claims claims = claimsJws.getBody();
                request.setAttribute("claims", claims);
            } catch (final SignatureException e) {
                throw new ServletException("Invalid token.");
            }
        }

        filterChain.doFilter(servletRequest, servletResponse);
    }
}

我非常清楚这里比较纯文本密码等的不良做法。我只是想让它暂时发挥作用。 token 已正确生成并返回。 token 也已正确设置到本地存储,但在向 /rest/users 路由发出 get 请求时,会返回 404。 java端没有错误。

最佳答案

果然如我所料,我确实是个白痴。正如上面用户提到的,我的服务映射到 /users/ ,我需要的是 protected 版本 /rest/users 。因此,在我的 UserController 旁边,我创建了 UserResource.java ,如下所示:

import com.acb.app.model.User;
import com.acb.app.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/rest")
public class UserResource {

    @Autowired
    private UserService userService;

    @RequestMapping("/users")
    public List<User> findAllUsers() {
        return userService.getAllUsers();
    }
}

这利用了 JwtFilter 并允许我保护我的路由。希望这对其他人有帮助。

关于java - Angular 与 Spring Boot 后端在获取 JWT 后在现有路线上返回 404,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51810833/

相关文章:

java - 使用Ebean,填充存储另一个相关实体属性的实体列表的属性值

html - 代码标签在 Angular html 模板中不起作用

jquery - 如何使用 Angular 动画复制 jQuery SlideUp()/slideDown()?

java - 替换某些字符组合

java - 具有 2 个参数的静音命令 (ArrayIndexOutOfBoundsException)

java - 错误 : <identifier> expected in java hadoop

java - org.springframework.orm.hibernate5.HibernateQueryException : Video is not mapped [from Video]

spring - 如何从 Spring WebClient 获取响应 json

spring - 收到来自 SMTP 主机 : smtp. yandex.ru、端口 : 465, 的错误问候响应:[EOF]] 与根本原因 Yandex

angular - 它相当于 Blazor 中的 Angular/Vue 事件发射吗?