项目实现的功能:
.登录的验证码功能
.操作员的认证和授权功能
.操作员的对应角色的更新
.部门管理
.员工管理
.菜单管理
.职称管理
登录和授权过程:
先将登录接口进行放行,请求会先通过jwt tokenfilter,如果前端请求没有携带jwttoken,那么就是未认证的状态,jwttokenfilter将会直接放行,在login接口中会首先比对验证码是否正确,如果正确的话,在usernamepasswordauthenticationfilter中调用重写过的loadUserByUsername方法,先将传入的用户名信息去数据库中查询,将查询得到的用户信息封装成UserDetails对象返回,然后进行密码的校验,如果也通过的话就将用户信息和权限信息封装成Authentication对象存入redis中,并通过用户名生成一个jwt令牌返回给前端。
用户登录之后访问其他接口时,首先会通过jwt tokenfilter进行判断,如果此时携带有jwt令牌,在jwt tokenfilter中对前端携带的jwt进行解析得到对应用户的用户名,根据此用户名去redis中查询对应的用户信息和权限信息,如果redis中存在用户信息,就将用户信息封装成Authentication对象,并存在SecurityContextHolder中。
在CustomFilter中,会获取请求的url,将可以访问该url的角色保存成一个String[],如果没有匹配的url默认为登录即可访问,将需要的角色名设置为"ROLE_LOGIN",之后请求会经过FilterSecurityIntecopter,如果所需要的角色是"ROLE_LOGIN",则直接放行,否则的话判断当前登录用户的角色和SpringSecurity所需要的角色是否匹配,如果匹配则允许访问,不匹配则报异常。
package com.xxxx.server.config.filter;
import com.xxxx.server.Utils.RedisCache;
import com.xxxx.server.config.security.JwtTokenUtil;
import com.xxxx.server.pojo.Admin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @program: yeb
* @description: Jwt的过滤器
* @author: 周文杰
* @create: 2022-04-14 21:11
**/
@Component
public class jwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Value("${jwt.tokenHeader}")
private String tokenHeader;
@Value("${jwt.tokenHead}")
private String tokenHead;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private RedisCache redisCache;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
FilterChain filterChain) throws ServletException, IOException {
//前端携带token的格式应该为:tokenHeader:tokenHead jwt令牌
String header = httpServletRequest.getHeader(tokenHeader);
if (!StringUtils.hasText(header)){
filterChain.doFilter(httpServletRequest,httpServletResponse);
return;
}
//存在token
String username = null;
if (header != null && header.startsWith(tokenHead)){
String authToken = header.substring(tokenHead.length());
username = jwtTokenUtil.getUserNameFromToken(authToken);
// //token存在,但是未登录
// if (username != null && SecurityContextHolder.getContext().getAuthentication() == null){
// //登录
// UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// //验证token是否有效,重新设置用户对象
// if (jwtTokenUtil.validateToken(authToken,userDetails)){
// UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
// authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
// SecurityContextHolder.getContext().setAuthentication(authenticationToken);
// }
// }
}
//从redis中获取用户信息
String redisKey="user_name"+username;
Admin user = redisCache.getCacheObject(redisKey);
if (ObjectUtils.isEmpty(user)){
throw new RuntimeException("用户信息不存在");
}
//验证通过后将用户信息存入SecurityContextHolder中
UsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(user,null,user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(httpServletRequest,httpServletResponse);
}
}
问题:使用自己创建的用户时,无法从redis中获取用户信息?