当前位置:   article > 正文

Spring boot 入门教程-token验证_springboot accesstoken

springboot accesstoken

 

这篇博客是在 Spring boot 入门教程-全局异常处理及日志输出  的基础上完成的。

我们在做项目时比如商城项目,有的页面的打开是需要登陆的而有的页面则不需要,所以这里就需要一种验证是否登录,或者登录是否过期,这里说一种token令牌+拦截器的方式。

生成token 使用JWT。

1.引入

  1. <dependency>
  2. <groupId>io.jsonwebtoken</groupId>
  3. <artifactId>jjwt</artifactId>
  4. <version>0.9.0</version>
  5. </dependency>

2.生成token令牌的工具类

  1. public class TokenUtils {
  2. /**
  3. * 签名秘钥
  4. */
  5. public static final String SECRET = "admin";
  6. /**
  7. * 生成token
  8. *
  9. * @param id 一般传入userName
  10. * @return
  11. */
  12. public static String createJwtToken(String id) {
  13. String issuer = "www.xxxx.com";
  14. String subject = "xxxx@126.com";
  15. long ttlMillis = 3600000;
  16. return createJwtToken(id, issuer, subject, ttlMillis);
  17. }
  18. /**
  19. * 生成Token
  20. *
  21. * @param id 编号
  22. * @param issuer 该JWT的签发者,是否使用是可选的
  23. * @param subject 该JWT所面向的用户,是否使用是可选的;
  24. * @param ttlMillis 签发时间 (有效时间,过期会报错)
  25. * @return token String
  26. */
  27. public static String createJwtToken(String id, String issuer, String subject, long ttlMillis) {
  28. // 签名算法 ,将对token进行签名
  29. SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
  30. // 生成签发时间
  31. long nowMillis = System.currentTimeMillis();
  32. Date now = new Date(nowMillis);
  33. // 通过秘钥签名JWT
  34. byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(SECRET);
  35. Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
  36. // Let's set the JWT Claims
  37. JwtBuilder builder = Jwts.builder().setId(id)
  38. .setIssuedAt(now)
  39. .setSubject(subject)
  40. .setIssuer(issuer)
  41. .signWith(signatureAlgorithm, signingKey);
  42. // if it has been specified, let's add the expiration
  43. if (ttlMillis >= 0) {
  44. long expMillis = nowMillis + ttlMillis;
  45. Date exp = new Date(expMillis);
  46. builder.setExpiration(exp);
  47. }
  48. // Builds the JWT and serializes it to a compact, URL-safe string
  49. return builder.compact();
  50. }
  51. // Sample method to validate and read the JWT
  52. public static Claims parseJWT(String jwt) {
  53. // This line will throw an exception if it is not a signed JWS (as expected)
  54. Claims claims = Jwts.parser()
  55. .setSigningKey(DatatypeConverter.parseBase64Binary(SECRET))
  56. .parseClaimsJws(jwt).getBody();
  57. return claims;
  58. }
  59. public static void main(String[] args) {
  60. System.out.println(TokenUtils.createJwtToken("11111"));
  61. }
  62. }

3.注入当前登录用户注解

  1. /**
  2. * @BelongsProject: JDTaste
  3. * @BelongsPackage: com.jdtaste.common.util
  4. * @Author:
  5. * @CreateTime: 2018-07-04 15:39
  6. * @Description: 在Controller的方法参数中使用此注解,该方法在映射时会注入当前登录的User对象
  7. */
  8. @Target(ElementType.PARAMETER) // 可用在方法的参数上
  9. @Retention(RetentionPolicy.RUNTIME) // 运行时有效
  10. public @interface CurrentUser {
  11. }

4.需要登录的标记注解

  1. /**
  2. * @BelongsProject: JDTaste
  3. * @BelongsPackage: com.jdtaste.common.util
  4. * @Author:
  5. * @CreateTime: 2018-07-04 15:38
  6. * @Description: 在需要登录验证的Controller的方法上使用此注解
  7. */
  8. @Target({ElementType.METHOD})// 可用在方法名上
  9. @Retention(RetentionPolicy.RUNTIME)// 运行时有效
  10. public @interface LoginRequired {
  11. }

5.编辑拦截器

  1. /**
  2. * @BelongsProject:
  3. * @BelongsPackage: com.jdtaste.jdtastesso.web.intercepter
  4. * @Author:
  5. * @CreateTime: 2018-07-04 09:50
  6. * @Description: 拦截器
  7. */
  8. public class AuthenticationInterceptor implements HandlerInterceptor {
  9. public final static String ACCESS_TOKEN = "accessToken";
  10. @Resource
  11. IUserBaseService userBaseService;
  12. // 在业务处理器处理请求之前被调用
  13. @Override
  14. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  15. // 如果不是映射到方法直接通过
  16. if (!(handler instanceof HandlerMethod)) {
  17. return true;
  18. }
  19. HandlerMethod handlerMethod = (HandlerMethod) handler;
  20. Method method = handlerMethod.getMethod();
  21. // 判断接口是否需要登录
  22. LoginRequired methodAnnotation = method.getAnnotation(LoginRequired.class);
  23. // 有 @LoginRequired 注解,需要认证
  24. if (methodAnnotation != null) {
  25. // 判断是否存在令牌信息,如果存在,则允许登录
  26. String accessToken = request.getHeader("Authorization");
  27. if (null == accessToken) {
  28. throw new CommonException(401, "无token,请重新登录");
  29. } else {
  30. // 从Redis 中查看 token 是否过期
  31. Claims claims;
  32. try{
  33. claims = TokenUtils.parseJWT(accessToken);
  34. }catch (ExpiredJwtException e){
  35. response.setStatus(401);
  36. throw new CommonException(401, "token失效,请重新登录");
  37. }catch (SignatureException se){
  38. response.setStatus(401);
  39. throw new CommonException(401, "token令牌错误");
  40. }
  41. String userName = claims.getId();
  42. UserBase user = userBaseService.findUserByAccount(userName);
  43. if (user == null) {
  44. response.setStatus(401);
  45. throw new CommonException(401, "用户不存在,请重新登录");
  46. }
  47. // 当前登录用户@CurrentUser
  48. request.setAttribute(CurrentUserConstants.CURRENT_USER, user);
  49. return true;
  50. }
  51. } else {//不需要登录可请求
  52. return true;
  53. }
  54. }
  55. // 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
  56. @Override
  57. public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
  58. }
  59. // 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
  60. @Override
  61. public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
  62. }
  63. }

 

  1. /**
  2. * @BelongsProject:
  3. * @BelongsPackage: com.jdtaste.jdtastesso.web.intercepter.auth
  4. * @Author:
  5. * @CreateTime: 2018-07-04 15:45
  6. * @Description: 当前用户
  7. */
  8. public class CurrentUserConstants {
  9. /**
  10. * 当前用户参数名
  11. */
  12. public final static String CURRENT_USER = "CurrentUser";
  13. }

 

6.自定义参数解析器

  1. /**
  2. *
  3. * @BelongsPackage: com.jdtaste.jdtastesso.web.intercepter.auth
  4. * @Author:
  5. * @CreateTime: 2018-07-04 15:42
  6. * @Description: 自定义参数解析器
  7. * 增加方法注入,将含有 @CurrentUser 注解的方法参数注入当前登录用户
  8. */
  9. public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {
  10. /*
  11. * supportsParameter:用于判定是否需要处理该参数分解,返回true为需要,并会去调用下面的方法resolveArgument。
  12. *resolveArgument:真正用于处理参数分解的方法,返回的Object就是controller方法上的形参对象。
  13. *
  14. * */
  15. @Override
  16. public boolean supportsParameter(MethodParameter parameter) {
  17. System.out.println("----------supportsParameter-----------" + parameter.getParameterType());
  18. return parameter.getParameterType().isAssignableFrom(UserBase.class)//判断是否能转成UserBase 类型
  19. && parameter.hasParameterAnnotation(CurrentUser.class);//是否有CurrentUser注解
  20. }
  21. @Override
  22. public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
  23. NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
  24. System.out.println("--------------resolveArgument-------------" + parameter);
  25. UserBase user = (UserBase) webRequest.getAttribute(CurrentUserConstants.CURRENT_USER, RequestAttributes.SCOPE_REQUEST);
  26. if (user != null) {
  27. return user;
  28. }
  29. throw new MissingServletRequestPartException(CurrentUserConstants.CURRENT_USER);
  30. }
  31. }

7.将拦截器和参数解析器加入容器

  1. /**
  2. * @BelongsProject:
  3. * @BelongsPackage: com.jdtaste.jdtastesso.conf
  4. * @Author:
  5. * @CreateTime: 2018-07-04 10:03
  6. * @Description: 配置URLInterceptor拦截器,以及拦截路径
  7. */
  8. @EnableWebMvc
  9. @Configuration
  10. public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
  11. @Override
  12. public void addInterceptors(InterceptorRegistry registry) {
  13. // addPathPatterns 用于添加拦截规则
  14. // excludePathPatterns 用户排除拦截
  15. registry.addInterceptor(authenticationInterceptor())
  16. .addPathPatterns("/*/*");
  17. super.addInterceptors(registry);
  18. }
  19. @Override
  20. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
  21. argumentResolvers.add(currentUserMethodArgumentResolver());
  22. super.addArgumentResolvers(argumentResolvers);
  23. }
  24. @Bean
  25. public CurrentUserMethodArgumentResolver currentUserMethodArgumentResolver() {
  26. return new CurrentUserMethodArgumentResolver();
  27. }
  28. /**
  29. * 解决 拦截器中注入bean 失败情况出现
  30. * addArgumentResolvers方法中 添加
  31. * argumentResolvers.add(currentUserMethodArgumentResolver());
  32. */
  33. @Bean
  34. public AuthenticationInterceptor authenticationInterceptor() {
  35. return new AuthenticationInterceptor();
  36. }
  37. }
  38. argumentResolvers.add(currentUserMethodArgumentResolver());
  39. super.addArgumentResolvers(argumentResolvers);
  40. }
  41. @Bean
  42. public CurrentUserMethodArgumentResolver currentUserMethodArgumentResolver() {
  43. return new CurrentUserMethodArgumentResolver();
  44. }
  45. /**
  46. * 解决 拦截器中注入bean 失败情况出现
  47. * addArgumentResolvers方法中 添加
  48. * argumentResolvers.add(currentUserMethodArgumentResolver());
  49. */
  50. @Bean
  51. public AuthenticationInterceptor authenticationInterceptor() {
  52. return new AuthenticationInterceptor();
  53. }
  54. }

8.Controller

  1. @LoginRequired
  2. @RequestMapping(value = "/token")
  3. public String token(@CurrentUser UserBase userBase,String account,String token) {
  4. log.info(account+"----"+token);
  5. log.info("----"+userBase.getAccount());
  6. log.info("params==" + userBase.toString());
  7. if (userBaseService.findUserByAccount(userBase.getAccount()) == null) {
  8. return "账号不存在";
  9. } else {
  10. UserBase result = null;
  11. result = userBaseService.login(userBase);
  12.             //生成token
  13.             //String accessToken=TokenUtils.createJwtToken(userBase.getAccount());
  14. if (result == null) {
  15. return "密码错误";
  16. } else {
  17. return "SUCCESS";
  18. }
  19. }
  20. }
  21. @LoginRequired
  22. @RequestMapping(value = "/token")
  23. public String token(@CurrentUser UserBase userBase,String account,String token) {
  24. log.info(account+"----"+token);
  25. log.info("----"+userBase.getAccount());
  26. log.info("params==" + userBase.toString());
  27. if (userBaseService.findUserByAccount(userBase.getAccount()) == null) {
  28. return "账号不存在";
  29. } else {
  30. UserBase result = null;
  31. result = userBaseService.login(userBase);
  32.             //生成token
  33.             //String accessToken=TokenUtils.createJwtToken(userBase.getAccount());
  34. if (result == null) {
  35. return "密码错误";
  36. } else {
  37. return "SUCCESS";
  38. }
  39. }
  40. }

 

9.前端发送请求 (axios)

  1. _this.$http.post('/api/user/login',
  2. this.login,
  3. {
  4. headers: {
  5. Authorization: JSON.parse(sessionStorage.getItem("loginUser")).accessToken,
  6. }
  7. }).then((res) => {
  8. console.log(res);
  9. });

10 .请求过程 

拦截器-->参数解析器-->controler-->拦截器

注意:参数解析器当第一个返回true 才执行第二个方法

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/368068
推荐阅读
相关标签
  

闽ICP备14008679号