@requestMapping(value = "/login", method = RequestMethod.POST) public String login(@RequestBody User login) throws ServletException { String jwtToken = ""; if (login.getEmail() == null || login.getPassword() == null) { throw new ServletException("Please fill in username and password"); } String email = login.getEmail(); String password = login.getPassword(); User user = userService.findByEmail(email); if (user == null) { throw new ServletException("User email not found."); } String pwd = user.getPassword(); if (!password.equals(pwd)) { throw new ServletException("Invalid login. Please check your name and password."); } jwtToken = Jwts.builder().setSubject(email).claim("roles", "user").setIssuedAt(new Date()) .signWith(SignatureAlgorithm.HS256, "secretkey").compact(); return jwtToken; }
当用户使用正确的密码登录时,他会收到以下令牌:eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJtQGFib3VsbGFpdGUubWUiLCJyb2xlcyI6InVzZXIiLCJpYXQiOjE0ODYyMDYwNjd9.nbppPf6DIl3f3d79EGouJ1cN599R0JELjAiGHXUqSD0这个“令牌”之后会用于客户端对服务器的后续API调用系列请求。这里的标准方法是发送具有“Bearer”令牌的授权报头。HTTP头部将是:authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJtQGFib3VsbGFpdGUubWUiLCJyb2xlcyI6InVzZXIiLCJpYXQiOjE0ODYyMDU3MTh9.N3quHsQvaqzpCLIPhm7-5_gvmK9TxVrKygCEiis27hSpringBootJwtApplication会配置一个过滤器。Servlet过滤器可以使用HttpRequests做各种事情,我们将使用这个过滤器来保护我们的“安全”端点。你可以看到SpringBootJwtApplication类将我们的JwtFilter配置为只对“/ secure / *”端点执行操作:final FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new JwtFilter()); registrationBean.addUrlPatterns("/secure/*"); return registrationBean;
2这样,当我们调用/user/login没有授权头时,它不会出错。过滤器负责检查正确的授权头是否存在以及Http头部中的令牌是否有效:public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) req; final HttpServletResponse response = (HttpServletResponse) res; final String authHeader = request.getHeader("authorization"); if ("OPTIONS".equals(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); chain.doFilter(req, res); } else { if (authHeader == null || !authHeader.startsWith("Bearer ")) { throw new ServletException("Missing or invalid Authorization header"); } final String token = authHeader.substring(7); try { final Claims claims = Jwts.parser().setSigningKey("secretkey").parseClaimsJws(token).getBody(); request.setAttribute("claims", claims); } catch (final SignatureException e) { throw new ServletException("Invalid token"); } chain.doFilter(req, res); } }
Jwt解析器使用与签名相同的密钥来检查令牌签名。如果密钥有效,我们就在请求对象中存储包含一些用户信息(电子邮件,角色)的“Claims”,以便API端点可以使用它。最后但并非最不重要的是,我们调用chain.doFilter这样,没有它,请求不会传递到我们的控制器。现在我们有了过滤器,我们可以定义一些漂亮的超级安全的API方法,比如:@RequestMapping("/user/users") public String loginSuccess() { return "Login Successful!"; }
您可以使用像Postman这样的REST客户端演示这个例子。,