提示:这里穿插了数据库持久层的操作,使用MybatisPlus框架作为数据库持久层的技术,熟悉掌握它吧!!!
package com.xuguoguo.common;
import com.xuguoguo.entity.SysUser;
import com.xuguoguo.exception.UserCountLockException;
import com.xuguoguo.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
@Package: com.xuguoguo.common
@ClassName: ResponseData
@Author: XuGuoGuo
@CreateTime: 2023/12/12-20:26
@Description: 自定义UserDetails
*/
@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {
@Autowired
SysUserService sysUserService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser sysUser=sysUserService.getByUsername(username);
if(sysUser==null){
throw new UsernameNotFoundException("用户名或者密码错误!");
}else if("1".equals(sysUser.getStatus())){
throw new UserCountLockException("该用户账号被封禁,具体请联系管理员!");
}
return new User(sysUser.getUsername(),sysUser.getPassword(),getUserAuthority());
}
public List<GrantedAuthority> getUserAuthority() {
return new ArrayList<>();
}
}
public interface SysUserService extends IService<SysUser> {
SysUser getByUsername(String username);
}
/**
* @author xuguoguo
* @description 针对表【sys_user】的数据库操作Service实现
* @createDate 2023-12-05 20:20:08
*/
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser>
implements SysUserService{
@Override
public SysUser getByUsername(String username) {
return getOne(new QueryWrapper<SysUser>().eq("username",username));
}
}
public class UserCountLockException extends AuthenticationException {
public UserCountLockException(String msg, Throwable t) {
super(msg, t);
}
public UserCountLockException(String msg) {
super(msg);
}
}
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = RuntimeException.class)
public Result handler(RuntimeException e){
log.error("项目运行时异常:--------->{}"+e.getMessage());
return Result.error(e.getMessage());
}
}
@Autowired
private MyUserDetailsServiceImpl myUserDetailsService;
//密码加密处理方式
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService);
}
此时数据表的记录:[密码是加密后的123456]
提示:这里还是需要使用到springsecurity中的认证的内容块,需要多理解它!!!
由此可知,直接响应回SpringSecurity的默认登录页面,这样是不行的!
package com.xuguoguo.common;
import com.xuguoguo.entity.SysUser;
import com.xuguoguo.service.SysUserService;
import com.xuguoguo.utils.JwtUtils;
import com.xuguoguo.utils.StringUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
/**
@Package: com.xuguoguo.common
@ClassName: MyJwtAuthenticationFilter
@Author: XuGuoGuo
@CreateTime: 2023/12/6-19:19
@Description:
*/
@Slf4j
public class MyJwtAuthenticationFilter extends BasicAuthenticationFilter {
@Autowired
private SysUserService sysUserService;
@Autowired
private MyUserDetailsServiceImpl myUserDetailsService;
private static final String URL_WHITELIST[] ={
"/login",
"/logout",
"/captcha",
"/password",
"/image/**"
} ;
public MyJwtAuthenticationFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
String token = request.getHeader("token");
System.out.println("请求url:"+request.getRequestURI());
// 如果token是空 或者 url在白名单里,则放行
if(StringUtil.isEmpty(token) || new ArrayList<String>(Arrays.asList(URL_WHITELIST)).contains(request.getRequestURI())){
chain.doFilter(request,response);
return;
}
try {
Claims claims = JwtUtils.parseJWT(token);
log.info("正在执行jwt认证过滤:{}",claims.toString());
String username = claims.getSubject();
SysUser sysUser = sysUserService.getByUsername(username);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(username,null,
//======== 此处预留根据用户编号查询用户拥有的权限信息 ========
myUserDetailsService.getUserAuthority());
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
chain.doFilter(request,response);
} catch (ExpiredJwtException e) {
throw new JwtException("Token过期");
} catch (SignatureException e) {
throw new JwtException("Token验证不通过");
} catch (Exception e) {
throw new JwtException("Token不存在");
}
}
}
@Bean
MyJwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
MyJwtAuthenticationFilter jwtAuthenticationFilter=new MyJwtAuthenticationFilter(authenticationManager());
return jwtAuthenticationFilter;
}
//===========================自定义过滤器配置=========================
.and()
.addFilter(jwtAuthenticationFilter());
@Component
public class MyJwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=UTF-8");
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
ResponseData<Object> result = new ResponseData<>
("请求异常",HttpServletResponse.SC_UNAUTHORIZED,"认证失败,请登录!");
String jsonStr = JSONUtil.toJsonStr(result);
outputStream.write(jsonStr.getBytes("UTF-8"));
outputStream.flush();
outputStream.close();
}
}
@Component
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=UTF-8");
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
outputStream.write(JSONUtil.toJsonStr(Result.ok("注销成功")).getBytes());
outputStream.flush();
outputStream.close();
}
}
提示:这个小结中主要实现了是使用了数据库的用户信息表来实现登录,并且自定义了用户过滤认证、认证异常处理以及注销的基本的操作实现引导!!!
本章的第四小节完毕,敬请期待后续更新(可留言需要学习哪方面的内容哈)!如果需要源码或者工具的朋友们可关注微信公众号"锅锅编程生活"或者扫描二维码关注回复关键字/后台留言获取即可!