您的位置:首页 > 数据库 > Redis

cookie+session+redis+springAop判断用户是否登录

2020-02-04 07:36 309 查看

采用前后端分离,后端只提供接口,前端对接口进行调用

1.前端用户发送登录请求

login.html

<div class="form-container sign-in-container">
<form action="#" id="l-form">
<h1>登录</h1>
<span>或使用您的帐号</span>
<input id="l-username" type="text" placeholder="用户名" name="username">
<input id="l-password" type="password" placeholder="密码" name="password">
<a href="#">忘记密码?</a>
<button id="btn-login">登录</button>
</form>
</div>

login.js

$("#btn-login").click(function () {
$.ajax({
url: "/api/login",
type: "POST",
data: {
"username": $("#l-username").val(),
"password": $("#l-password").val(),
},
success: function (result) {
//根据服务器端返回的结果进行相应处理
});
return false;
});

2.服务器端将SessionId存入到Redis并将SessionId返回

ApiController.java

/**
* method: post
* url: /login
* description: 登录
*/
@PostMapping(Api.LOGIN)
public Result login(String username, String password, HttpSession session) {
User user = userService.selectUserByUsername(username);
if (password != null && salt != null && realPassword.equals(user.getPassword())) {
//存入redis key:username value:sessionId
redisService.set(username, session.getId());
return Result.success().add("username", username).add("sessionId",session.getId());
}
}

3.前端将SessionId保存到Cookie(这里使用到了jquery.cookie.js插件)

$.cookie(username, sessionId, {expires: 7, path: '/'});

4.前端必须是登录状态才能发送的请求(比如注销):

logout.js

function logout() {
var username=window.location.href.split("?")[1].split("=")[1];
var sessionId=$.cookie(username);
if(sessionId==null){  //如果cookie中没有sessionId则不能发送logout请求
alert(username+"尚未登录");
window.location.href="/user/index";
return;
}
$.ajax({
url: "/api/logout",
type:"post",
data: {
username: username,
sessionId:sessionId, //将sessionId也发送过去
},
success:function(result){
var errorCode=result.errorCode;
var reason=result.reason;
switch (errorCode) {
case 8004:
alert(reason);
break;
}
window.location.href="/user/index";
}
})
}

5.服务器端通过SpringAop对需要是登录状态才能进行的请求进行拦截,检查用户是否登录

LoginStatusAop.java

@Aspect
@Component
@Slf4j
public class LoginStatusAop {
@Autowired
private RedisService redisService;

//这里需要使用@Around而不要用@Before,因为@Before不能使用ProceedJoinPoint,只能使用JoinPoint.
//而@Before的话即使你return了或者throw Exception还是会往下执行
//而@Around只有调用了proceed()才会往下执行
@Around(value = "doApi()")
public Object doApiBefore( ProceedingJoinPoint pjp) throws Throwable {
try{
Object[] args = pjp.getArgs();
String username = args[0].toString();
String sessionId = args[1].toString();
String realSessionId = redisService.get(username); //如果前端发送过来的sessionId和服务器端的sessionId一致才会请求到/logout api
if(realSessionId!=null&&sessionId.equals(realSessionId)){
return pjp.proceed();
}
}catch (Exception e){
return Result.failure(Constant.FAILURE_CODE,Constant.LOGIN_USER_IDLE_CODE,Constant.LOGIN_USER_IDLE);
}
return Result.failure(Constant.FAILURE_CODE,Constant.LOGIN_USER_IDLE_CODE,Constant.LOGIN_USER_IDLE);
}

//我将所有需要登录才能进行请求的api方法都设置为了protected
//这里要注意不能设置为private,不然会无效,原因自行百度
//不知道此条切点表达式意思的话自行百度
@Pointcut("execution(protected * com.selenium.aaa.common.controller.ApiController.*(..))")
public void doApi() {
}
}

6.服务器端在注销后删除Redis中的SessionId

ApiController

/**
* method: post
* url: /logout
* description: 退出
*/
@PostMapping(Api.LOGOUT)
protected Result logout(String username,String sessionId) {
if(redisService.delete(username)){ //删除redis中的sessionId
return Result.success();
}else{
return Result.failure();
}
}

注意:这样还是又一个问题,暂时不知道如何解决,当用户异常退出时(比如直接关闭浏览器),/logout没有被调用,导致redis中的sessionId没有被清除,我想到的办法只能给cookie和redis设置expire(超时),但显然这是有问题的。

  • 点赞
  • 收藏
  • 分享
  • 文章举报
Selenium. 发布了23 篇原创文章 · 获赞 1 · 访问量 879 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: