设计思路

用户发出登录请求,带着用户名和密码到服务器经行验证,服务器验证成功就在后台生成一个token返回给客户端

客户端将token存储到cookie中,服务端将token存储到redis中,可以设置存储token的有效期。

后续客户端的每次请求资源都必须携带token,这里放在请求头中,服务端接收到请求首先校验是否携带token,以及token是否和redis中的匹配,若不存在或不匹配直接拦截返回错误信息(如未认证)。

token管理:生成、校验、解析、删除

token:这里使用userId_UUID的形式

有效期:使用Redis key有效期设置(每次操作完了都会更新延长有效时间)

销毁token:删除Redis中key为userId的内容

token存储:客户端(Cookie)、服务端(Redis)

Cookie的存取操作(jquery.cookie插件)

Redis存取(StringRedisTemplate)

实现

(本demo只是个小例子,还有很多不足,用于实际环境还需要根据实际考虑更多的问题)

【Redis操作类】

package com.bpf.tokenAuth.utils;

import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.StringRedisTemplate;

import org.springframework.stereotype.Component;

@Component

public class RedisClient {

public static final long TOKEN_EXPIRES_SECOND = 1800;

@Autowired

private StringRedisTemplate redisTpl;

/**

* 向redis中设值

* @param key 使用 a:b:id的形式在使用rdm进行查看redis情况时会看到分层文件夹的展示形式,便于管理

* @param value

* @return

*/

public boolean set(String key, String value) {

boolean result = false;

try {

redisTpl.opsForValue().set(key, value);

result = true;

} catch (Exception e) {

e.printStackTrace();

}

return result;

}

/**

* 向redis中设置,同时设置过期时间

* @param key

* @param value

* @param time

* @return

*/

public boolean set(String key, String value, long time) {

boolean result = false;

try {

redisTpl.opsForValue().set(key, value);

expire(key, time);

result = true;

} catch (Exception e) {

e.printStackTrace();

}

return result;

}

/**

* 获取redis中的值

* @param key

* @return

*/

public String get(String key) {

String result = null;

try {

result = redisTpl.opsForValue().get(key);

} catch (Exception e) {

e.printStackTrace();

}

return result;

}

/**

* 设置key的过期时间

* @param key

* @param time

* @return

*/

public boolean expire(String key, long time) {

boolean result = false;

try {

if(time > 0) {

redisTpl.expire(key, time, TimeUnit.SECONDS);

result = true;

}

} catch (Exception e) {

e.printStackTrace();

}

return result;

}

/**

* 根据key删除对应value

* @param key

* @return

*/

public boolean remove(String key) {

boolean result = false;

try {

redisTpl.delete(key);

result = true;

} catch (Exception e) {

e.printStackTrace();

}

return result;

}

}

【Token管理类】

package com.bpf.tokenAuth.utils.token;

import java.util.UUID;

import org.apache.commons.lang3.StringUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import com.bpf.tokenAuth.utils.RedisClient;

@Component

public class RedisTokenHelp implements TokenHelper {

@Autowired

private RedisClient redisClient;

@Override

public TokenModel create(Integer id) {

String token = UUID.randomUUID().toString().replace("-", "");

TokenModel mode = new TokenModel(id, token);

redisClient.set(id == null ? null : String.valueOf(id), token, RedisClient.TOKEN_EXPIRES_SECOND);

return mode;

}

@Override

public boolean check(TokenModel model) {

boolean result = false;

if(model != null) {

String userId = model.getUserId().toString();

String token = model.getToken();

String authenticatedToken = redisClient.get(userId);

if(authenticatedToken != null && authenticatedToken.equals(token)) {

redisClient.expire(userId, RedisClient.TOKEN_EXPIRES_SECOND);

result = true;

}

}

return result;

}

@Override

public TokenModel get(String authStr) {

TokenModel model = null;

if(StringUtils.isNotEmpty(authStr)) {

String[] modelArr = authStr.split("_");

if(modelArr.length == 2) {

int userId = Integer.parseInt(modelArr[0]);

String token = modelArr[1];

model = new TokenModel(userId, token);

}

}

return model;

}

@Override

public boolean delete(Integer id) {

return redisClient.remove(id == null ? null : String.valueOf(id));

}

}

【拦截器逻辑】

package com.bpf.tokenAuth.interceptor;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import org.springframework.web.method.HandlerMethod;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.bpf.tokenAuth.annotation.NoneAuth;

import com.bpf.tokenAuth.constant.NormalConstant;

import com.bpf.tokenAuth.entity.JsonData;

import com.bpf.tokenAuth.utils.JsonUtils;

import com.bpf.tokenAuth.utils.token.TokenHelper;

import com.bpf.tokenAuth.utils.token.TokenModel;

@Component

public class LoginInterceptor extends HandlerInterceptorAdapter {

@Autowired

private TokenHelper tokenHelper;

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

System.out.println(11);

// 如果不是映射到方法直接通过

if (!(handler instanceof HandlerMethod)) {

return true;

}

//如果被@NoneAuth注解代表不需要登录验证,直接通过

HandlerMethod handlerMethod = (HandlerMethod) handler;

Method method = handlerMethod.getMethod();

if(method.getAnnotation(NoneAuth.class) != null) return true;

//token验证

String authStr = request.getHeader(NormalConstant.AUTHORIZATION);

TokenModel model = tokenHelper.get(authStr);

//验证通过

if(tokenHelper.check(model)) {

request.setAttribute(NormalConstant.CURRENT_USER_ID, model.getUserId());

return true;

}

//验证未通过

response.setCharacterEncoding("UTF-8");

response.setContentType("application/json; charset=utf-8");

response.getWriter().write(JsonUtils.obj2String(JsonData.buildError(401, "权限未认证")));

return false;

}

}

【登录逻辑】

package com.bpf.tokenAuth.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.DeleteMapping;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import com.bpf.tokenAuth.annotation.NoneAuth;

import com.bpf.tokenAuth.constant.MessageConstant;

import com.bpf.tokenAuth.constant.NormalConstant;

import com.bpf.tokenAuth.entity.JsonData;

import com.bpf.tokenAuth.entity.User;

import com.bpf.tokenAuth.enums.HttpStatusEnum;

import com.bpf.tokenAuth.mapper.UserMapper;

import com.bpf.tokenAuth.utils.token.TokenHelper;

import com.bpf.tokenAuth.utils.token.TokenModel;

@RestController

@RequestMapping("/token")

public class TokenController {

@Autowired

private UserMapper userMapper;

@Autowired

private TokenHelper tokenHelper;

@NoneAuth

@GetMapping

public Object login(String username, String password) {

User user = userMapper.findByName(username);

if(user == null || !user.getPassword().equals(password)) {

return JsonData.buildError(HttpStatusEnum.NOT_FOUND.getCode(), MessageConstant.USERNAME_OR_PASSWORD_ERROR);

}

//用户名密码验证通过后,生成token

TokenModel model = tokenHelper.create(user.getId());

return JsonData.buildSuccess(model);

}

@DeleteMapping

public Object logout(HttpServletRequest request) {

Integer userId = (Integer) request.getAttribute(NormalConstant.CURRENT_USER_ID);

if(userId != null) {

tokenHelper.delete(userId);

}

return JsonData.buildSuccess();

}

}

测试

【login.html】

Login

function login(){

$.ajax({

url: "/tokenAuth/token",

dataType: "json",

data: {'username':$("#username").val(), 'password':$("#password").val()},

type:"GET",

success:function(res){

console.log(res);

if(res.code == 200){

var authStr = res.data.userId + "_" + res.data.token;

//把生成的token放在cookie中

$.cookie("authStr", authStr);

window.location.href = "index.html";

}else alert(res.msg);

}

});

}

【index.html】

Index

function get(){

$.ajax({

url: "/tokenAuth/user/bpf",

dataType: "json",

type:"GET",

beforeSend: function(request) {

//将cookie中的token信息放于请求头中

request.setRequestHeader("authStr", $.cookie('authStr'));

},

success:function(res){

console.log(res);

}

});

}

function logout(){

$.ajax({

url: "/tokenAuth/token",

dataType: "json",

type:"DELETE",

beforeSend: function(request) {

//将cookie中的token信息放于请求头中

request.setRequestHeader("authStr", $.cookie('authStr'));

},

success:function(res){

console.log(res);

}

});

}

测试环境中两个页面login.html和index.html均当做静态资源处理

【未登录状态】

点击get按钮获取数据,由于没有携带token导致认证失败

【登录状态】

登录成功并跳转到index页面,并且生成cookie,这里没有设置cookie有效期,默认关闭浏览器失效

再次点击get按钮请求数据,请求成功

点击logout按钮销毁登录状态,然后再次请求数据

html登录状态验证,Token验证登录状态的简单实现相关推荐

  1. signature验证/salt验证/token验证的作用

    1.salt验证: salt是随机生成的一串字符,salt验证的作用是将生成的salt与加密的密码密文拼接后再次加密存储  这样可以是存储在数据库中的密码更加安全 2.signature验证: I.将 ...

  2. vue项目中实现用户登录以及token验证

    文章目录 前言 一.总体逻辑图 二.各环节涉及知识点以及代码 1.jwt(这里只说用法,至于为什么用它,详细可查官网) 2.返回token并存入vuex做持久化 3.路由守卫 4.axios请求拦截 ...

  3. springboot+vue jwt校验token 单点登录

    SSO(Single Sign On)模式 CAS单点登录.OAuth2 分布式,SSO(single sign on)模式:单点登录英文全称Single Sign On,简称就是SSO.它的解释是: ...

  4. app Token验证流程

    验证流程: 1:服务端接收到app发送的用户名和密码,进行登录验证. 如果登录验证错误,返回错误信息,用户名或者密码不存在. 2:验证通过.服务端生成一个唯一的token字符串返回给app端,app将 ...

  5. tp5.1实现Token验证

    生成Token /*** 创建 token* @param array $data 必填 自定义参数数组* @param integer $exp_time 必填 token过期时间 单位:秒 例子: ...

  6. 微信公众号服务器验证Token的完整步骤

    服务器验证Token验证分为以下及步骤 一,在微信公众号平台上设置 1.1打开微信公众号平台 1.2打开"开发"中的<基本配置> 1.3点击基本配置页面里的修改配置 1 ...

  7. k8s登录_用户名密码方式登录Kubernetes-Dashboard

    背景:默认安装完k8s集群和Dashboard之后都是使用token登录的,这样使用起来不是很方便,每次登录还要找到token才能登录. 本片文章使用用户和密码方式进行登录! 环境介绍 集群环境    ...

  8. WebApi用户登录验证及服务器端用户状态存取

    最近项目需要给手机端提供数据,采用WebApi的方式,之前的权限验证设计不是很好,这次采用的是Basic基础认证. 1.常见的认证方式 我们知道,asp.net的认证机制有很多种.对于WebApi也不 ...

  9. json web token 实践登录以及校验码验证

    去年我写了一篇介绍 jwt 的文章. 文章指出如果没有特别的用户注销及单用户多设备登录的需求,可以使用 jwt,而 jwt 的最大的特征就是无状态,且不加密. 除了用户登录方面外,还可以使用 jwt ...

最新文章

  1. R回归模型glm与lm的区别
  2. 智能车大赛AI视觉组培训第一弹——基础篇
  3. vuefullcalendar怎么判断切换上下月_六种区分对联上下联的方法
  4. 用sql语句获取连续整数id中,缺失的最小id和最大id
  5. 如果您在2015年编写过Java代码-这是您不容错过的趋势
  6. 前端学习(1059):ES6中的类和对象
  7. 网页自动关机代码HTML,win10系统打开邮件显示网页html源代码如何解决
  8. ubuntu 绑定网卡
  9. ESXi 内存回收机制
  10. python 网络渗透_python 网络编程(渗透与编程一)
  11. 多分类支持向量机及其Python实现
  12. 共轭梯度法(Conjugate Gradient)
  13. MATLAB与Hspice联合仿真
  14. 中国氨基酸表面活性剂市场前景展望与发展建议分析报告2022-2028年
  15. linux nfs 测试 读写,部署NFS与测试NFS
  16. EFI、UEFI、MBR、GPT的区别
  17. 用幻灯片征服全世界_NET为什么会征服世界NET很显然很像
  18. 未来科技感UI界面设计欣赏
  19. 绿茶集团在港上市申请再失效:王勤松夫妇为实控人,翻台率不及格
  20. 速度与AI兼得:荣耀Play“GPU Turbo”是什么大杀技?

热门文章

  1. python爬取新浪财经的股票信息
  2. iPad4 iOS6完美越狱
  3. 关于浅拷贝深拷贝那些事儿
  4. 2022分享三面阿里:Java 面试核心手册 +Java 电子书 + 技术笔记 + 学习视频
  5. CPU 中运算器的作用
  6. Java基础学习笔记及总结
  7. [附源码]JAVA+ssm食疗养生服务平台(程序+Lw)
  8. HuaWei ❀ IPv6组播地址
  9. 计算机等级证书有四个级别的说明
  10. 大学生网页作业设计HTML,库里网页