Spring Boot与JWT整合实现前后端分离的用户认证

前言

本篇使用java-jwt作为JWT库,与Spring Boot整合实现前后端分离架构中用户认证。
Spring Boot项目搭建参考:
[Spring Boot系列]1. 项目搭建之一

关于JWT的介绍参考:
JWT介绍以及java-jwt的使用

整合思路

  1. 后端提供登录服务,根据前端POST的用户名、密码产生Token。
  • 对用户名、密码验证通过后产生Token
  • Token中包含用户名、过期时间,使用用户密码作为密钥进行加盐加密。
  1. 前端获取该Token后,随后的请求附加该Token,后端获取Token解密,获取用户名,并且验证Token是否有效

实例步骤和代码

  1. 在pom.xml中导入JWT
		<!--JWT -->
		<dependency>
			<groupId>com.auth0</groupId>
			<artifactId>java-jwt</artifactId>
			<version>3.8.3</version>
		</dependency>
  1. 提供产生Token的服务,这里使用 /login, 控制器类是PermissController
@RestController
public class PermissController {
	@Autowired
	private UserService userService;

	@Autowired
	private PermissService permissService;

	@Autowired
	private BadouMessages badouMessages;

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@PostMapping("/login")
	public Object login(@RequestBody User user) {
		StatusResponse statusResponse = new StatusResponse(Status.SUCCESS, null);
		if (user != null && user.getId() != null) {
			User userFromDb = userService.get(user.getId());
			if (userFromDb == null) {
				statusResponse.setMessage(badouMessages.get("userNotExist", new String[] { user.getId() }));
				statusResponse.setStatus(Status.FAIL);
			} else {
				if (!userFromDb.getPassword().equals(user.getPassword())) {
					statusResponse.setMessage(badouMessages.get("userNotExist", new String[] { user.getId() }));
					statusResponse.setStatus(Status.FAIL);
				} else {
					Map map = new HashMap();
					String token = permissService.getToken(userFromDb);
					map.put("token", token);
					map.put("user", userFromDb);
					return map;
				}
			}
		} else {
			statusResponse.setMessage(badouMessages.get("nullMsg", new String[] { "User Id" }));
			statusResponse.setStatus(Status.FAIL);

		}

		return statusResponse;
	}
}
  1. 定义拦截器拦截验证Token
/**
 * @Title: AuthenticationInterceptor.java
 * @Package com.osxm.badou.base
 * @Description: TODO
 * @author oscarchen
 * @date 2019年10月25日
 * @version V1.0
 */
package com.osxm.badou.base;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import com.osxm.badou.base.BadouConstants.Status;
import com.osxm.badou.base.service.PermissService;

/**
 * @ClassName: AuthenticationInterceptor
 * @Description: TODO
 * @author oscarchen
 */
public class AuthenticationInterceptor implements HandlerInterceptor {

	@Autowired
	PermissService permissService;

	@Override
	public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
			Object object) throws Exception {
		String token = httpServletRequest.getHeader("token");
		String errMsg = null;
		// 非映射方法直接通过
		if (!(object instanceof HandlerMethod)) {
			return true;
		}
		//
		if (token == null) {
			errMsg = "没有token,请登录";
		} else {
			try {
				permissService.verifyToken(token);
			} catch (BadouException e) {
				errMsg = e.getMessage();
			}
		}
		if (errMsg != null) {
			StatusResponse statusResponse = new StatusResponse(Status.FAIL, errMsg);
			ResponseUtil.returnJsonMessage(httpServletResponse, statusResponse);
			return false;
		}
		return true;
	}
}

  1. 配置拦截器拦截需要验证用户的请求
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor()).addPathPatterns("/demos");
    }

    @Bean
    public AuthenticationInterceptor authInterceptor() {
        return new AuthenticationInterceptor();
    }
}
  1. 加密、解密Token的服务代码
@Service
public class PermissServiceImpl implements PermissService {

    @Autowired
    private BadouMessages dadouMessages;

    @Autowired
    private UserService userService;

    public String getToken(User user) {
        String token = "";
        token = JWT.create().withAudience(user.getId())// 把用户ID存入Token
                .sign(Algorithm.HMAC256(user.getPassword()));// 用户密码作为密钥,使用HMAC(消息散列鉴别码)算法加密生成Token
        return token;
    }

    public User verifyToken(String token) throws BadouException {
        User user = getUser(token);
        if (user != null) {
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
            try {
                jwtVerifier.verify(token);
            } catch (JWTVerificationException e) {
                throw new BadouException(dadouMessages.get("invalidtoken"));
            }
        } else {
            throw new BadouException(dadouMessages.get("invalidtoken"));
        }
        return user;
    }

    private User getUser(String token) {
        User user = null;
        try {
            String userId = JWT.decode(token).getAudience().get(0);
            user = userService.get(userId);
            user.setId(userId);
        } catch (JWTDecodeException j) {

        }
        return user;
    }

}

示例项目Git路径。
待补充,或私信索取

如需详细了解相关机制和代码参考,参见
前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之一

前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之二

发布了591 篇原创文章 · 获赞 486 · 访问量 463万+

猜你喜欢

转载自blog.csdn.net/oscar999/article/details/102735948