springboot +jjwt+注解实现需登录才能调用接口

1.开发需要登录才能进行操作的自定义注解NeedLogin,后面可以写在需要登陆后操作的接口上

package com.songzhen.howcool.auth;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedLogin {
boolean required() default true;
}

2.开发拦截器(Interceptor),预处理全部请求

package com.songzhen.howcool.auth;

import com.alibaba.fastjson.JSON;
import com.songzhen.howcool.model.enums.RetCodeEnum;
import com.songzhen.howcool.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map; public class AuthenticationInterceptor implements HandlerInterceptor { @Autowired
private RedisTemplate<String, String> redisTemplate; /**
* 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller
* 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception { // 判断对象是否是映射到一个方法,如果不是则直接通过
if (!(object instanceof HandlerMethod)) {
// instanceof运算符是用来在运行时指出对象是否是特定类的一个实例
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
//检查方法是否有NeedLogin注解,无则跳过认证
if (method.isAnnotationPresent(NeedLogin.class)) {
NeedLogin needLogin = method.getAnnotation(NeedLogin.class);
if (needLogin.required()) {
// 从HTTP请求头中获取TOKEN信息
String token = httpServletRequest.getHeader("Authorization"); // HTTP请求头中TOKEN解析出的用户信息
String uid = JwtUtil.getUid(token);
String userName = JwtUtil.getUserName(token);
String realName = JwtUtil.getRealName(token); // 检查TOKEN
if (!checkToken(token)) {
// TOKEN错误时,提示用户登录
Map<String, Object> retMap = new HashMap<>(16);
retMap.put("code", RetCodeEnum.ACCOUNT_UNAUTHORIZED.getCode());
retMap.put("msg", RetCodeEnum.ACCOUNT_UNAUTHORIZED.getDesc());
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.getWriter().append(JSON.toJSONString(retMap));
return false;
} // 组装用户信息到REQUEST中
Map<String, Object> currentUser = new HashMap<>(16);
currentUser.put("uid", uid);
currentUser.put("userName", userName);
currentUser.put("realName", realName);
httpServletRequest.setAttribute("currentUser", currentUser); return true;
}
}
return true;
} /**
* 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object, ModelAndView modelAndView) throws Exception {
long now = System.currentTimeMillis();
} /**
* 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中
*/
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
} /**
* 检查TOKEN
*
* @param token token
* 要校验的token
* @return boolean
* true:通过 false:失败
*/
private boolean checkToken(String token) {
// ------------------------认证------------开始-----------------
if (null == token) {
return false;
} // 获取TOKEN中的用户信息
String uid = JwtUtil.getUid(token); // 根据uid从redis中获取用户tokenInRedis
String tokenInRedis = redisTemplate.opsForValue().get(uid);
if (null == tokenInRedis) {
// 如果REDIS异常,返回成功保证正常业务可以继续处理
return true;
} // HTTP请求头中TOKEN解析出的用户信息
String userName = JwtUtil.getUserName(token);
String realName = JwtUtil.getRealName(token);
String deviceId = JwtUtil.getDeviceId(token);
long expireIn = JwtUtil.getExpireIn(token);
// REDIS服务器中TOKEN解析出的用户信息
String userNameInRedis = JwtUtil.getUserName(tokenInRedis);
String realNameInRedis = JwtUtil.getRealName(tokenInRedis);
String deviceIdInRedis = JwtUtil.getDeviceId(tokenInRedis);
long expireInInRedis = JwtUtil.getExpireIn(tokenInRedis); if (null == userName || null == realName || null == deviceId) {
return false;
}
if (null == userNameInRedis || null == realNameInRedis || null == deviceIdInRedis) {
return false;
}
// 判断TOKEN是否过期
if (expireIn != expireInInRedis) {
return false;
}
if (expireIn < System.currentTimeMillis()) {
return false;
}
// ------------------------认证------------结束-----------------
return true;
} }

3.开发拦截器配置类

package com.songzhen.howcool.config;

import com.songzhen.howcool.auth.AuthenticationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}

4.在Controller中需要登录才能操作的方法上加上注解NeedLogin

package com.songzhen.howcool.controller;

import com.songzhen.howcool.entity.QueryUserEntity;
import com.songzhen.howcool.entity.UserLoginEntity;
import com.songzhen.howcool.auth.NeedLogin;
import com.songzhen.howcool.biz.UserBizService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest;
import java.util.Map; /**
* 用户相关.
* <p>用户相关<br>
* 用户相关
*
* @author Lucas
* @date 2018/8/9
*/
@RestController
@RequestMapping("**/v1/user")
public class UserController { private static final Logger logger = LoggerFactory.getLogger(UserController.class); @Autowired
private UserBizService userBizService; /**
* 登录
*/
@PostMapping("login")
public Map<String, Object> login(@RequestBody UserLoginEntity userLoginEntity) {
logger.info("login input params userLoginEntity={}", userLoginEntity);
return userBizService.login(userLoginEntity.getUserName(), userLoginEntity.getPassword(), userLoginEntity.getDeviceId());
} /**
* 登出
*
* @param request request
*/
@NeedLogin
@PostMapping("logout")
public Map<String, Object> logout(HttpServletRequest request) {
Map<String,Object> currentUser = (Map<String,Object>)request.getAttribute("currentUser"); return userBizService.logout(currentUser.get("uid").toString());
} /**
* 列表用户
*/
@NeedLogin
@PostMapping("pageUser")
public Map<String, Object> pageUser(@RequestBody QueryUserEntity queryUserEntity) {
logger.info("login input params queryUserEntity={}", queryUserEntity);
return userBizService.pageUsers(queryUserEntity);
} }

5.GitHub上源代码地址

https://github.com/songzhen110/howcool.git

【实战】Springboot +jjwt+注解实现需登录才能操作的更多相关文章

  1. SpringBoot版不需要配置文件注解获取当前登录用户

    本文讯(2019年3月30日 飞快的蜗牛博客)   我是一个懒人,很久不写博客,想起来看到也不一定会写,只有心血来潮的时候写写,"钱塘江上潮信来,今日方知我是我"...... 空杯 ...

  2. SpringBoot实现基于token的登录验证

    一.SpringBoot实现基于token的登录验证 基于token的登录验证实现原理:客户端通过用户名和密码调用登录接口,当验证数据库中存在该用户后,将用户的信息按照token的生成规则,生成一个字 ...

  3. Asp.Net Core 2.0 项目实战(10) 基于cookie登录授权认证并实现前台会员、后台管理员同时登录

    1.登录的实现 登录功能实现起来有哪些常用的方式,大家首先想到的肯定是cookie或session或cookie+session,当然还有其他模式,今天主要探讨一下在Asp.net core 2.0下 ...

  4. SpringBoot —— AOP注解式拦截与方法规则拦截

    AspectJ是一个面向切面的框架,它扩展了Java语言.AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件. SpringBoot中AOP的使用 ...

  5. 常见的springmvc、SpringBoot的注解

    springMvc的常用注解 : @Controller :用于标记在一个类上,使用它标记的类就是一个springmcv Controller对象,分发处理器将会扫描使用了该注解 的类的方法,并检测该 ...

  6. SpringBoot(14)—注解装配Bean

    SpringBoot(14)-注解装配Bean SpringBoot装配Bean方式主要有两种 通过Java配置文件@Bean的方式定义Bean. 通过注解扫描的方式@Component/@Compo ...

  7. Spring Boot 实战 —— MyBatis(注解版)使用方法

    原文链接: Spring Boot 实战 -- MyBatis(注解版)使用方法 简介 MyBatis 官网 是这么介绍它自己的: MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过 ...

  8. Springboot 拦截器配置(登录拦截)

    Springboot 拦截器配置(登录拦截) 注意这里环境为springboot为2.1版本 1.编写拦截器实现类,实现接口   HandlerInterceptor, 重写里面需要的三个比较常用的方 ...

  9. 接近8000字的Spring/SpringBoot常用注解总结!安排!

    0.前言 大家好,我是 Guide 哥!这是我的 221 篇优质原创文章.如需转载,请在文首注明地址,蟹蟹! 本文已经收录进我的 75K Star 的 Java 开源项目 JavaGuide:http ...

随机推荐

  1. word doc转pdf

    from win32com.client import constants, gencache # TODO pip install pywin32 -i http://mirrors.aliyun. ...

  2. Python_内置函数和匿名函数

    楔子 在讲新知识之前,我们先来复习复习函数的基础知识. 问:函数怎么调用? 函数名() 如果你们这么说...那你们就对了!好了记住这个事儿别给忘记了,咱们继续谈下一话题... 来你们在自己的环境里打印 ...

  3. git免密拉取代码

    里介绍通过ssh公钥的方式免密拉取代码 以linux服务器为例,windows方式是一样的 1.用命令生成ssh key ssh-keygen -t rsa -C "xx@xxxcom&qu ...

  4. spring(四):IoC

    IoC-Inversion of Control,即控制反转 IoC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制. 理解IoC的关键:"谁控制谁,控制什么,为何是反 ...

  5. CompletableFuture--给future调用增加回调或聚合操作

    CompletableFuture--增大内存节省时间.整合多个future调用,来减少时间 例如:第一个future 返回时1s,第二个返回时2s,第三个返回是3s   CompletableFut ...

  6. Java爬虫学习(1)之爬取新浪微博博文

    本次学习采用了webmagic框架,完成的是一个简单的小demo package com.mieba.spiader; import us.codecraft.webmagic.Page; impor ...

  7. 2020ICPC 博弈题 纳新一百的石子游戏

    https://ac.nowcoder.com/acm/contest/4010/C 这道题为尼姆博弈的其中一种裸类型: 要求求出前(1~n)堆的必胜方案. 对于这种类型,假如我们现在就前k堆,那么我 ...

  8. MySQL连接池详解

    使用场景数据库连接是一种关键的.有限的.昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正是针对 ...

  9. js的变量(01)

    变量的声明用的修饰符 var ,let ,const var是普通变量      var   变量名  = 变量值         可以重复定义可以多次修改 let是es6新加的语法   let 变量 ...

  10. 关于我 & 关于这个博客

    关于我 OIer,初一在读,蒟蒻,普及组选手,只拿过两次PJ2=,实乃菜也 喜欢数学,OI,OI 上主要研究高级数据结构(如平衡树)和一些不那么暴力的算法(如分块) 打不动 CF . 关于这个博客 是 ...