Token优势原理步骤与实现
Token优势原理步骤与实现token的优势步骤实现前端vue登入成功获取tokenvue中自定义请求,请求中携带token后端登入,获取token并保存再redis中根据token对普通用户认证
token的优势
Token 完全由应用管理,所以它可以避开同源策略(所谓的同源,指的是协议,域名,端口相同)。
Token 可以避免 CSRF 攻击(CSRF利用cookie进行请求伪造,token可以不用到cookie)。
Token 可以是无状态的,可以在多个微服务间共享。
步骤
[步骤引用于] https://blog.csdn.net/u014322206/article/details/85089481
① 用户首次登录,将输入的账号和密码提交给服务器
② 服务器对账户密码校验,若账号和密码匹配则验证通过,登录成功,并生成一个token值,将其保存到数据库,并返回给客户端
③ 客户端拿到返回的token值将其保存在本地(如cookie/local storage),作为公共参数,以后每次请求服务器时都携带该token(放在响应头里),提交给服务器进行校验
④ 服务器接收到请求后,首先验证是否携带token,若携带则取出请求头里的token值与数据库存储的token进行匹配校验,服务器执行校验后续步骤。
⑤ 注意:用户每进行一次登录,登录成功后服务器都会更新一个token新值返回给客户端
实现
基础的实现,只有为登入与登入的校验,没有其他高级权限。
前端
vue登入成功获取token
登入并将获取的token放在localStorage中
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n50" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Roboto Mono", "Source Sans Pro", Monaco, courier, monospace !important; font-size: 0.85rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248) !important; position: relative !important; width: inherit; border: 1px solid rgb(244, 244, 244); -webkit-font-smoothing: initial; line-height: 1.43rem; border-radius: 2px; word-wrap: normal; margin: 0.8rem 0px !important; padding: 0.3rem 0px !important; color: rgb(52, 73, 94); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">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.userName+" 登入成功!");
}
}
)
// this.$router.go(-1);
}</pre>
vue中自定义请求,请求中携带token
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n34" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Roboto Mono", "Source Sans Pro", Monaco, courier, monospace !important; font-size: 0.85rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248) !important; position: relative !important; width: inherit; border: 1px solid rgb(244, 244, 244); -webkit-font-smoothing: initial; line-height: 1.43rem; border-radius: 2px; word-wrap: normal; margin: 0.8rem 0px !important; padding: 0.3rem 0px !important; color: rgb(52, 73, 94); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">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 从
}
});
}</pre>
后端登入,获取token并保存再redis中
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n59" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Roboto Mono", "Source Sans Pro", Monaco, courier, monospace !important; font-size: 0.85rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248) !important; position: relative !important; width: inherit; border: 1px solid rgb(244, 244, 244); -webkit-font-smoothing: initial; line-height: 1.43rem; border-radius: 2px; word-wrap: normal; margin: 0.8rem 0px !important; padding: 0.3rem 0px !important; color: rgb(52, 73, 94); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">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);
}
}
}</pre>
根据token对普通用户认证
使用spring的Aop对相应请求拦截验证。
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n69" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: "Roboto Mono", "Source Sans Pro", Monaco, courier, monospace !important; font-size: 0.85rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248) !important; position: relative !important; width: inherit; border: 1px solid rgb(244, 244, 244); -webkit-font-smoothing: initial; line-height: 1.43rem; border-radius: 2px; word-wrap: normal; margin: 0.8rem 0px !important; padding: 0.3rem 0px !important; color: rgb(52, 73, 94); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">@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;
}
}
}
}
</pre>
网友评论