赞
踩
jwt登录校验流程
Spring security 配置初始化
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
public static final String DONT_AUTHENTICATION_PROFIX = "/comm";
public static final String DONT_IMAGE_PROFIX = "/image";
public static final Set<String> PERMIT_ALL_URL = Sets.newHashSet(
DONT_AUTHENTICATION_PROFIX + "/**",
DONT_IMAGE_PROFIX + "/**"
);
// 用于knife4j
public static final Set<String> KNIFE4J = Sets.newHashSet(
"/doc.html/**",
"/webjars/**",
"/img.icons/**",
"/swagger-resources/**",
"/v2/**"
);
private static Logger logger = LoggerFactory.getLogger(ApplicationSecurity.class);
@Autowired
private MenuMapper menuMapper;
@Resource
private JWTAdminAuthenticationFilter jWTAdminAuthenticationFilter;
@Resource
private EntryPointUnauthorizedHandler entryPointUnauthorizedHandler;
@Resource
private RestAccessDeniedHandler restAccessDeniedHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
// 禁止页面嵌套 网站可以使用此功能来避免 点击劫持 攻击
http.headers().frameOptions().disable();
initAuth(http); // 初始化权限
// 基于token,所以不需要session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
//添加 接口权限
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers(KNIFE4J.toArray(new String[]{})).permitAll()
.antMatchers(PERMIT_ALL_URL.toArray(new String[]{})).permitAll()
.anyRequest().authenticated()
.and().headers().cacheControl();
// 自定义基于jwt拦截器
http.addFilterBefore(jWTAdminAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
// 自定义异常
http.exceptionHandling()
//处理没有认证的访问异常
.authenticationEntryPoint(entryPointUnauthorizedHandler)
// 处理没有权限时抛出的异常
.accessDeniedHandler(restAccessDeniedHandler);
}
/**
* 初始化系统权限内容
* @param http
*/
private void initAuth(HttpSecurity http) {
List<Menu> list = menuMapper.selectList(null);
try {
for (Menu auth : list) {
String role = auth.getGuid();
String name = auth.getMenuName();
String url = auth.getUrl();
if (StringUtils.isNotBlank(url)) {
http.authorizeRequests().antMatchers(url).hasRole(role);
}
logger.info("init all Authorities, name={}, role={}, url={}", name, role, url);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
自定义验证类
@Component
public class JWTAdminAuthenticationFilter extends OncePerRequestFilter {
private static final Logger log = LoggerFactory.getLogger(JWTAdminAuthenticationFilter.class);
@Autowired
private JWTHelperUtil jWTHelperUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException,
ServletException {
// 通过请求地址 判断是否需要进行token验证
authByPath(request, response);
chain.doFilter(request, response);
}
private void authByPath(HttpServletRequest request, HttpServletResponse response) {
String path = request.getServletPath();
String[] pp = path.split("/");
if (pp.length > 1) {
path = "/" + pp[1] + "/**";
}
// 判断是否knife4
boolean knife4jFlag = ApplicationSecurity.KNIFE4J.contains(path);
if (knife4jFlag) {
return;
}
// 判断是否进行权限认证
boolean authentication = ApplicationSecurity.PERMIT_ALL_URL.contains(path);
if (!authentication) {
authentication(request, response);
}
}
private void sendNotPermit(HttpServletResponse response) {
JSONObject jsonObj = new JSONObject();
try {
jsonObj.put("code", ServiceCode.TOKEN_INVALID.code);
jsonObj.put("msg", ServiceCode.TOKEN_INVALID.msg);
response.setContentType("application/json;charset=utf-8");
response.getOutputStream().write(jsonObj.toString().getBytes(StandardCharsets.UTF_8));
} catch (Exception e1) {
log.error("error={}", e1.getMessage(), e1);
}
}
private void authentication(HttpServletRequest request, HttpServletResponse response) {
String authHeader = request.getHeader("Authorization");
String tokenHead = "Bearer ";
if (StringUtils.isBlank(authHeader)) {
sendNotPermit(response);
return;
}
if (authHeader.startsWith(tokenHead)) {
String authToken = authHeader.substring(tokenHead.length());
try {
// 验证token
LoginUser mUserVo = jWTHelperUtil.verifyAdminToken(authToken);
// 把用户信息权限放到spring security 上下文当中
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(mUserVo, null, mUserVo.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (Exception e) {
log.error("error={}", e.getMessage(), e);
sendNotPermit(response);
}
}
}
}
JWT配置类
@Component
public class JWTHelperUtil {
private String JWT_SECRET = "wx_app_api_099888";
private int expires_secs = 60 * 60 * 24 * 7;
private static final String USER_INFO_KEY = "userInfo";
@Resource
private DataCache dataCacheDao;
/**
* 生成token 设置: # 过期时间 # 用户标识 #
*
* @param
* @return
*/
public String getToken(Object loginObj) {
try {
//HMAC256 加密
Algorithm algorithm = Algorithm.HMAC256(JWT_SECRET);
// 添加过期时间
Calendar expiresAt = Calendar.getInstance();
expiresAt.add(Calendar.SECOND, expires_secs);
String userStr = new ObjectMapper().writeValueAsString(loginObj);
// 生成token
String token = JWT.create().withClaim(USER_INFO_KEY, userStr).withExpiresAt(expiresAt.getTime()).sign(algorithm);
return token;
} catch (JWTVerificationException | JsonProcessingException exception) {
throw new ServiceBusinessException(ServiceCode.GEN_JWT_TOKEN_FAIL, exception.getMessage());
}
}
// 通过token 获取用户信息
public String getClaimByToken(String token) {
// 加密验证
Algorithm algorithm = Algorithm.HMAC256(JWT_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
// 获取用户信息
DecodedJWT jwt = verifier.verify(token);
String userStr = jwt.getClaim(USER_INFO_KEY).asString();
return userStr;
}
// 验证token
public LoginUser verifyAdminToken(String token) {
try {
// 加密验证
Algorithm algorithm = Algorithm.HMAC256(JWT_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
verifier.verify(token);
// 验证通过 获取该token登录信息 userId auth
LoginUser adminUser = dataCacheDao.getAdminLoginCacheData(token);
return adminUser;
} catch (JWTVerificationException exception) {
throw new ServiceBusinessException(ServiceCode.TOKEN_INVALID, exception.getMessage());
} catch (Exception e) {
e.printStackTrace();
throw new ServiceBusinessException(ServiceCode.TOKEN_INVALID, e.getMessage());
}
}
}
根据token获取用户缓存信息
@Component
public class DataCacheDaoImpl implements DataCache {
// 短信验证码缓存
private static final Cache<String, String> SMS_CACHE = CacheBuilder.newBuilder().maximumSize(100000)
.expireAfterWrite(5, TimeUnit.MINUTES) // 5分钟
.build();
//图形验证码缓存
private static final Cache<String, String> IMAGE_CACHE = CacheBuilder.newBuilder().maximumSize(100000)
.expireAfterWrite(5, TimeUnit.MINUTES) // 5分钟
.build();
// 用户登录
private static final Cache<String, LoginUser> LOGIN_CACHE = CacheBuilder.newBuilder().maximumSize(100000)
.expireAfterAccess(30, TimeUnit.MINUTES).build();
@Autowired
private JWTHelperUtil jWTHelperUtil;
@Autowired
private MenuMapper menuMapper;
@Value("${back.userName}")
private String SuperBackUserName;
@Override
public String getCacheValidCode(String key) {
return SMS_CACHE.getIfPresent(key);
}
@Override
public void setCacheValidCode(String key, String value) {
SMS_CACHE.put(key, value);
}
@Override
public String getCacheImageValidCode(String key) {
if (StringUtils.isBlank(key)) {
return null;
}
return IMAGE_CACHE.getIfPresent(key);
}
@Override
public void setCacheImageValidCode(String key, String value) {
IMAGE_CACHE.put(key,value);
}
@Override
public void setLoginCacheData(String key, LoginUser value) {
LOGIN_CACHE.put(key, value);
}
@Override
public String getCacheData(String key) {
if (StringUtils.isBlank(key)) {
return null;
}
return SMS_CACHE.getIfPresent(key);
}
@Override
public void setCacheData(String key, String value) {
SMS_CACHE.put(key, value);
}
@Override
public LoginUser getAdminLoginCacheData(String token) {
LoginUser loginUser = LOGIN_CACHE.getIfPresent(token);
if(Objects.isNull(loginUser)) {
String userStr = jWTHelperUtil.getClaimByToken(token);
JSONObject userObj = JSONObject.parseObject(userStr);
String type = userObj.getString("type");
if(Constants.LoginUserType.admin.name().equals(type)) {
loginUser = loadAdminUserData(token, userObj);
}/** else if(LoginUserType.api.name().equals(type)) {
} **/
loginUser.setType(type);
}
return loginUser;
}
private LoginUser loadAdminUserData(String token, JSONObject userObj) {
int userId = userObj.getInteger("id");
String username = userObj.getString("userName");
String type = userObj.getString("type");
// 查询用户所有权限
Set<GrantedAuthority> authorities = new HashSet<>();
List<Menu> list;
if(SuperBackUserName.equalsIgnoreCase(username)) {
LambdaQueryWrapper<Menu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.orderBy(true,true,Menu::getSort);
list = menuMapper.selectList(lambdaQueryWrapper);
} else {
list = menuMapper.userAuthority(userId);
}
for(Menu menu: list) {
authorities.add(new SimpleGrantedAuthority(String.format("%s%s",Constants.ROLE_PREFIX,menu.getGuid())));
}
LoginUser loginUser = new LoginUser(username, "-", authorities);
loginUser.setId(userId);
loginUser.setAuthList(MenuUtils.recursionMenu(0,list));
loginUser.setType(type);
setLoginCacheData(token, loginUser);
return loginUser;
}
private Set<String> getParentAndSelfAuth(List<Menu> self) {
List<Menu> all = menuMapper.selectList(null);
Set<String> returnSet = new HashSet<>();
Map<String, Menu> map = new HashMap<>();
for(Menu sa: all) {
map.put(sa.getGuid(), sa);
}
for(Menu auth :self) {
String guid = auth.getGuid();
returnSet.add(guid);
Menu sa = map.get(guid);
while(sa.getParentId()==null) {
sa = map.get(sa.getParentId());
returnSet.add(sa.getGuid());
}
}
return returnSet;
}
@Override
public LoginUser getApiLoginCacheData(String token) {
LoginUser loginUser = LOGIN_CACHE.getIfPresent(token);
return loginUser;
}
}
菜单工具类
public class MenuUtils {
//递归排序菜单及子菜单
public static List<Menu> recursionMenu(Integer parentId, List<Menu> menuList) {
List<Menu> list = new ArrayList<>();
for (Menu menu : menuList) {
Integer dataParentId = menu.getParentId();
if (ObjectUtils.equals(parentId,dataParentId)) {
List<Menu> menus = recursionMenu(menu.getId(), menuList);
menu.setChild(menus);
list.add(menu);
}
}
return list;
}
}
通过Spring security提取登录用户信息
public class CommUtils {
public static String randomUUID() {
return UUID.randomUUID().toString().replace("-", "").toLowerCase();
}
public static String serialId(String prefix) {
// 32位
String dStr = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()); // 17
String uuid = prefix + randomUUID(); // 18
return uuid.substring(0, 15) + dStr;
}
public static String getClientIp() {
HttpServletRequest request = getRequest();
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
public static String md5Encode(String password) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
throw new RuntimeException(e);
}
char[] charArray = password.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuilder hexValue = new StringBuilder();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
// 获取用户登录信息
public static LoginUser getLoginUserInfo() {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
if (authentication == null) {
return null;
}
Object principal = authentication.getPrincipal();
if (principal == null || principal instanceof String) {
return null;
}
return (LoginUser) principal;
}
public static HttpServletRequest getRequest() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return request;
}
public static HttpServletResponse getResponse() {
HttpServletResponse response=((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
return response;
}
public static String randomSmsValidCode() {
Random rand = new Random();
StringBuilder s = new StringBuilder(6);
for (int i = 0; i < 6; i++) {
s.append((int) (rand.nextInt(9)));
}
return s.toString();
}
public static void main(String[] args) {
System.out.println(md5Encode("123456"));
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。