Token优势原理步骤与实现
文章目录
token的优势
Token 完全由应用管理,所以它可以避开同源策略(所谓的同源,指的是协议,域名,端口相同)。
Token 可以避免 CSRF 攻击(CSRF利用cookie进行请求伪造,token可以不用到cookie)。
Token 可以是无状态的,可以在多个微服务间共享。
步骤
① 用户首次登录,将输入的账号和密码提交给服务器
② 服务器对账户密码校验,若账号和密码匹配则验证通过,登录成功,并生成一个token值,将其保存到数据库,并返回给客户端
③ 客户端拿到返回的token值将其保存在本地(如cookie/local storage),作为公共参数,以后每次请求服务器时都携带该token(放在响应头里),提交给服务器进行校验
④ 服务器接收到请求后,首先验证是否携带token,若携带则取出请求头里的token值与数据库存储的token进行匹配校验,服务器执行校验后续步骤。
⑤ 注意:用户每进行一次登录,登录成功后服务器都会更新一个token新值返回给客户端
实现
基础的实现,只有为登入与登入的校验,没有其他高级权限。
前端
vue登入成功获取token
登入并将获取的token放在localStorage中
checklogin: function() {
var _this=this;
this.postRequest('/login',{
username:this.ruleForm.name,
password: this.ruleForm.pass,
}).then(function(result) {
console.log(result.data);
if(result.data.status==200){
_this.$data.loginingname=_this.ruleForm.name;
window.localStorage.setItem("token", result.data.obj);//保存获取的token
console.log(_this.$data.userName+" 登入成功!");
}
}
)
// this.$router.go(-1);
}
vue中自定义请求,请求中携带token
export const postRequest = (url, params) => {
return axios({
method: 'post',
url: `${base}${url}`,
data: params,
transformRequest: [function (data) {
let ret = ''
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
return ret
}],
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'token' : window.localStorage.getItem("token"), //http头部添加 token 从
}
});
}
后端登入,获取token并保存再redis中
import ***
import java.util.UUID;
@Controller
@RequestMapping("/*")
public class LoginController {
private static final Logger logger= LoggerFactory.getLogger(LoginController.class);
@Autowired
UsersService usersService;
@Autowired
RedisTemplate redisTemplate;
@RequestMapping("/login")
@ResponseBody
public RespBean login(@Param("username") String username, @Param("password")String password, HttpServletResponse response){
Users users=usersService.selectUserByNameAndPass(username,password);
if(username==null){
return new RespBean(400,"用户名或密码错误",null);
}
else {
String token=UUID.randomUUID().toString();//根据java自带的UUID获取一个根据计算的字符串
logger.info("登入成功 token:"+token);
UserInfo userInfo=usersService.getUserInfoByUserid(users.getId());
redisTemplate.opsForValue().set(token,userInfo, Duration.ofMinutes(20));//再数据库中保存20分钟
return new RespBean(200,"登入成功",token);
}
}
}
根据token对普通用户认证
使用spring的Aop对相应请求拦截验证。
@Component
@Aspect
public class AuthorityAspect {
private static final Logger logger= LoggerFactory.getLogger(AuthorityAspect.class);
@Autowired
RedisTemplate redisTemplate;
@Pointcut("execution(* com.yzren.learnonline.controller.normaluser.*.*(..))")
public void authorityCheck() {
}
@Before("authorityCheck()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
HttpServletResponse response=attributes.getResponse();
String token =request.getHeader("token");
if(token==null){
logger.info("没有token 令牌");
response.setStatus(401);//在http协议中401状态代表无权限
return;
}else {
Long expire = redisTemplate.getExpire(token);//获取时间,看token是否过期,<0就未过期
if(expire<0){
response.setStatus(401);
return;
}
}
}
}