1.首先定义拦截器,在前置拦截获取认证信息,取出UserDetails中保存的username,通过mapper接口查询数据库用户信息对象,保存至SecurityContextHolderd 当前线程,以便后续随时在程序中获取用户信息
package com.youdu.wuhan2020.config;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.youdu.wuhan2020.entity.SysUser;
import com.youdu.wuhan2020.mapper.SysUserMapper;
import com.youdu.wuhan2020.utils.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import java.util.Collection;
import java.util.List;
/**
* 定义一个Interceptor 非常简单方式也有几种,我这里简单列举两种 1、类 要实现Spring 的HandlerInterceptor 接口 2、类
* 继承实现了HandlerInterceptor 接口的类,例如 已经提供的实现了HandlerInterceptor
* 接口的抽象类HandlerInterceptorAdapter
*
* @author 刘彦军 !!!除了定义此类,还需要将自定义的拦截器,注册到WebMvcConfigurer中,拦截器才起作用
* 之前我们在xml中配置拦截路径等,springboot我们需要继承WebMvcConfigurerAdapter类
* 不过springBoot2.0以上 WebMvcConfigurerAdapter 方法过时, 有两种替代方案:
* 1、继承WebMvcConfigurationSupport 2、实现WebMvcConfigurer
* 但是继承WebMvcConfigurationSupport会让Spring-boot对mvc的自动配置失效。根据项目情况选择。
* 现在大多数项目是前后端分离,并没有对静态资源有自动配置的需求所以继承WebMvcConfigurationSupport也未尝不可。
*/
@Slf4j
@Component
public class TokenHandlerInterceptor implements HandlerInterceptor {
//需要提前以@bean的方式注入拦截器,否则sysUserMapper为null;
//原因是因为拦截器的加载在springcontext之前,所以自动注入的mapper是null
@Autowired
private SysUserMapper sysUserMapper;
// 最终拦截
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
//log.info("最终拦截--在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行,主要是用于进行资源清理工作");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
// 后置拦截+统计总访问数
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
//log.info("后置拦截--请求处理之后进行调用,但是在视图被渲染之前,即Controller方法调用之后");
}
//
// 前置拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
//System.out.println("前置拦截在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication instanceof OAuth2Authentication) {
OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) authentication;
Authentication userAuthentication = oAuth2Authentication.getUserAuthentication();
//获取用户的account,这里就是UserDetails类 中返回的SecurityUser的name属性,这个name可以扩展
String account = userAuthentication.getName();
SysUser sysUser = new SysUser();
sysUser.setAccount(account);
List<SysUser> page = sysUserMapper.page(sysUser, null);
SysUser sysUser1 = null;
if (!CollectionUtils.isNullOrEmpty(page)) {
sysUser1 = page.get(0);
}
//角色数组
Collection<? extends GrantedAuthority> authorities = userAuthentication.getAuthorities();
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser1, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
return true;
}
}
2.将拦截器以@bean的方式进行注入spring容器,并且在springMVC中注册此拦截器
package com.youdu.wuhan2020.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 其实以前都是继承WebMvcConfigurerAdapter类 不过springBoot2.0以上 WebMvcConfigurerAdapter 方法过时
* 从源码上可以看出,WebMvcConfigurerAdapter类对WebMvcConfigurer接口进行了实现,不过都是空实现。
* ,java版本1.8 接口可以定义defult方法,那么WebMvcConfigurerAdapter这个适配类也就没有意义了,所以被抛弃
* 有两种替代方案:
* 1、继承WebMvcConfigurationSupport
* 2、实现WebMvcConfigurer
* 注意!!!
* 但是继承WebMvcConfigurationSupport会让Spring-boot对mvc的自动配置失效。
* 比如说默认静态资源路径的访问会失效,以及swagger的映射路径,等等(继承需要自己重新做静态资源路径的配置)
* 根据项目情况选择。现在大多数项目是前后端分离,
* 并没有对静态资源有自动配置的需求所以继承WebMvcConfigurationSupport也未尝不可。
*
* @author 刘彦军
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
// 继承WebMvcConfigurerAdapter类,注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 传入自定义的拦截器
registry.addInterceptor(tokenHandlerInterceptor())
// 拦截所有的请求
.addPathPatterns("/**");
}
@Bean
public TokenHandlerInterceptor tokenHandlerInterceptor() {
return new TokenHandlerInterceptor();
}
// @Override
// public void addResourceHandlers(ResourceHandlerRegistry registry) {
// registry.addResourceHandler(new String[]{"/lyj/**"})
// .addResourceLocations(new String[]{"classpath:/static/"});
// registry.addResourceHandler(new String[]{"swagger-ui.html"})
// .addResourceLocations(new String[]{"classpath:/META-INF/resources/"});
// registry.addResourceHandler(new String[]{"/webjars/**"})
// .addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"});
// }
}
3.在程序中取出线程中保存的用户对象,存的时候是sysUser,所有取得时候可以直接转
SysUser sysUser=(SysUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return "用户name:" +sysUser.getAccount();