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. WebRTC笔记(一)

    来源<WebRTC权威指南> 1 WebRTC特点 对等连接(Peer Connection):浏览器与浏览器(万维网上的任意两个通信终端)之间的连接(P2P) 信令服务器:在浏览器和对等 ...

  2. 安装node.js后npm不可用

    安装node.js后npm不可用 最近要用Vue做项目,依赖node.js,于是按官网下载安装node 下载地址:https://nodejs.org/en/download/ 网上也有很多教程这里就 ...

  3. Jenkins - 基于 Docker 的 Jenkins 安装

    概述 安装 Jenkins 基于 Docker 这个有点 水一发 的性质... 场景 学习 Jenkins 第一步, 当然是安装 但是 安装的方法 很多 Jenkins 是基于 Java 的 所以是个 ...

  4. 在手机浏览器中判断App是否已安装

    从网上搜到之前手机中判断App是否安装可以通过onblur事件+定时器来实现. 但现在要做这个功能时,按网上的说法已经不能实现了.因为现在浏览器中打开App,window不会触发onblur事件. 在 ...

  5. arcgis计算X坐标值、Y坐标值

    arcgis计算X坐标值.Y坐标值 要计算的字段上点击右键,选择计算几何,弹出计算几何对话框.可以设置属性.坐标系.单位等.

  6. Python 字符串格式化操作 - format方法

    建议使用format()方法 字符串操作 对于 %, 官方以及给出这种格式化操作已经过时,在 Python 的未来版本中可能会消失. 在新代码中使用新的字符串格式.因此推荐大家使用format()来替 ...

  7. appium---切换webview时报错

    在上一篇中简单介绍了如何查看webview和切换到webview的方法,可能第一次切换webview的时候会报错“Error: session not created exception: Chrom ...

  8. gulp 常用方法 任务 插件

    执行gulp 任务 gulp taskname (default任务不输入名称亦可:gulp) var gulp = require("gulp"); gulp.task(&quo ...

  9. Windows引用opencv静态库

    参考博客:https://www.cnblogs.com/sysuzyq/p/6183568.html

  10. go基础_数组

    数组有2种赋值方式 一种明确指定长度,另一种从赋值数目指定长度 package main import "fmt" func main() { //数组赋值方式1,指定长度 arr ...