實現了部落格的退出登入
使用SpringSecurity框架,配合redis和token實現
package com.huanf.controller;
import com.huanf.domain.ResponseResult;
import com.huanf.domain.User;
import com.huanf.enums.AppHttpCodeEnum;
import com.huanf.exception.SystemException;
import com.huanf.service.BlogLoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 35238
* @date 2023/7/22 0022 21:31
*/
@RestController
public class BlogLoginController {
@Autowired
//BlogLoginService是我們在service目錄寫的介面
private BlogLoginService blogLoginService;
@PostMapping("/login")
//ResponseResult是我們在huanf-framework工程裡面寫的實體類
public ResponseResult login(@RequestBody User user){
//如果使用者在進行登入時,沒有傳入'使用者名稱'
if(!StringUtils.hasText(user.getUserName())){
// 提示'必須要傳使用者名稱'。AppHttpCodeEnum是我們寫的列舉類。SystemException是我們寫的統一異常處理的類
throw new SystemException(AppHttpCodeEnum.REQUIRE_USERNAME);
}
return blogLoginService.login(user);
}
@PostMapping("/logout")
public ResponseResult logout(){
return blogLoginService.logout();
}
}
package com.huanf.service.impl;
import com.huanf.domain.LoginUser;
import com.huanf.domain.ResponseResult;
import com.huanf.domain.User;
import com.huanf.service.BlogLoginService;
import com.huanf.utils.BeanCopyUtils;
import com.huanf.utils.JwtUtil;
import com.huanf.utils.RedisCache;
import com.huanf.vo.BlogUserLoginVo;
import com.huanf.vo.UserInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.Objects;
/**
* @author 35238
* @date 2023/7/22 0022 21:39
*/
@Service
//認證,判斷使用者登入是否成功
public class BlogLoginServiceImpl implements BlogLoginService {
@Autowired
//AuthenticationManager是security官方提供的介面
private AuthenticationManager authenticationManager;
@Autowired
//RedisCache是我們在huanf-framework工程的config目錄寫的類
private RedisCache redisCache;
@Override
public ResponseResult login(User user) {
//封裝登入的使用者名稱和密碼
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());
//在下一行之前,封裝的資料會先走UserDetailsServiceImpl實現類,這個實現類在我們的huanf-framework工程的service/impl目錄裡面
Authentication authenticate = authenticationManager.authenticate(authenticationToken);
//上面那一行會得到所有的認證使用者資訊authenticate。然後下一行需要判斷使用者認證是否透過,如果authenticate的值是null,就說明認證沒有透過
if(Objects.isNull(authenticate)){
throw new RuntimeException("使用者名稱或密碼錯誤");
}
//獲取userid
LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
String userId = loginUser.getUser().getId().toString();
//把這個userid透過我們寫的JwtUtil工具類轉成密文,這個密文就是token值
String jwt = JwtUtil.createJWT(userId);
//下面那行的第一個引數: 把上面那行的jwt,也就是token值儲存到Redis。存到時候是鍵值對的形式,值就是jwt,key要加上 "bloglogin:" 字首
//下面那行的第二個引數: 要把哪個物件存入Redis。我們寫的是loginUser,裡面有許可權資訊,後面會用到
redisCache.setCacheObject("bloglogin:"+userId,loginUser);
//把User轉化為UserInfoVo,再放入vo物件的第二個引數
UserInfoVo userInfoVo = BeanCopyUtils.copyBean(loginUser.getUser(), UserInfoVo.class);
BlogUserLoginVo vo = new BlogUserLoginVo(jwt,userInfoVo);
//封裝響應返回
return ResponseResult.okResult(vo);
}
//-----------------------------------退出登入------------------------------------------
@Override
public ResponseResult logout() {
//獲取token,然後解析token值獲取其中的userid。SecurityContextHolder是security官方提供的類
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//LoginUser是我們寫的類
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
//獲取userid
Long userid = loginUser.getUser().getId();
//在redis根據key來刪除使用者的value值,注意之前我們在存key的時候,key是加了'bloglogin:'字首
redisCache.deleteObject("bloglogin:"+userid);
//封裝響應返回
return ResponseResult.okResult();
}
}