1.获取请求设备进行注册
1.1 mobile的依赖添加。其他swagger以及springboot基本依赖请自行添加。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mobile</artifactId>
<version>1.5.22.RELEASE</version>
</dependency>
1.2先将获取请求设备的Bean注入到mvc之中。
@Component
public class MvcConf implements WebMvcConfigurer {
@Bean
public DeviceHandlerMethodArgumentResolver
deviceHandlerMethodArgumentResolver() {
return new DeviceHandlerMethodArgumentResolver();
}
@Override
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(deviceHandlerMethodArgumentResolver());
}
}
2.手动实现拦截器
2.1创建用户实体,设计的数据表中并无Device相关字段,所以实体使用时,为了方便,直接通过@Transient注解添加到以映射的实体类中。
@Table(name="sys_user")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SysUser implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 编号
*/
@Id
private String id;
/**
* 归属公司
*/
private String companyId;
/**
* 归属部门
*/
private String officeId;
/**
* 登录名
*/
private String loginName;
/**
* 密码
*/
private String password;
/**
* 可逆密码
*/
private String password2;
/**
* 姓名
*/
private String name;
/**
* 邮箱
*/
private String email;
/**
* 电话
*/
private String phone;
/**
* 手机
*/
private String mobile;
/**
* 用户类型
*/
private String userType;
/**
* 是否可登录
*/
private String loginFlag;
/**
* 删除标记
*/
private String delFlag;
/**
* 安全密匙
*/
private String securityKey;
/**
* 判断是pc、手机、pad
*/
@Transient
private Device device;
2.2UserAccountHolder对ThreadLocal相关的操作
就是相关本地线程的获取与使用。
public class UserAccountHolder {
private UserAccountHolder() {
}
private static final ThreadLocal<SysUser> threadLocal = new ThreadLocal<>();
public static SysUser getUser() {
return threadLocal.get();
}
public static void setUser(final SysUser user) {
threadLocal.set(user);
}
public static void clear() {
threadLocal.remove();
}
}
2.3token的枚举。
public enum HttpHeaderKeyEnums {
/**
* 用户token
*/
TOKEN("token","登录用Token");
private String code;
private String desc;
HttpHeaderKeyEnums(String code, String desc) {
this.code = code;
this.desc = desc;
}
public String getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
2.3继承OncePerRequestFilter这个拦截器,实现token的获取与校验,设备类型的获取。
其中的AuthCacheService就是一个缓存的的获取,我这用的ehcache实现实现的,有多个配置实现类,比较繁琐暂时就不粘出来了。我本人其实更倾向于用redies,你们可以试试。
public class AuthFilter extends OncePerRequestFilter {
private PathMatcher ignoreUrlMatcher = new AntPathMatcher();
@Autowired
private AuthCacheService authCacheService;
private String[] ignoreURLs = {
"/",
"/error",
"/auth/login",
"/webjars/**",
"/swagger-resources/**",
"/v2/**",
"/swagger-ui.html",
"/socket/**",
"/integration/**",
"/desktop.html/**",
"/static/**",
"/simulator/**"
};
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
if (request.getMethod().equalsIgnoreCase(HttpMethod.OPTIONS.name())) {
return;
}
String token = request.getHeader(HttpHeaderKeyEnums.TOKEN.getCode()) == null ? request.getParameter(HttpHeaderKeyEnums.TOKEN.getCode()) : request.getHeader(HttpHeaderKeyEnums.TOKEN.getCode());
if (StringUtils.isBlank(token)) {
this.noLogin(response);
return;
}
// 登录后存入缓存的用户信息,跟这次请求的一个对比
if (!authCacheService.containsLoginToken(token)) {
/**
* 未登录
*/
this.noLogin(response);
return;
}
/**
* 已登录
*/
// 验证成功后,获取用户全部信息
SysUser user = authCacheService.getLoginToken(token);
// 获取设备信息放入实体中
user.setDevice(DeviceUtils.getCurrentDevice(request));
// 将完整的用户实体添加的ThreadLocal中
UserAccountHolder.setUser(user);
// 执行
filterChain.doFilter(request, response);
} finally {
UserAccountHolder.clear();
}
}
@SneakyThrows
private void noLogin(HttpServletResponse response) {
response.setHeader(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
response.sendError(HttpStatus.FORBIDDEN.value(), "未登录");
}
// 路径放行
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String requestPath = getRequestPath(request);
for (String url : ignoreURLs) {
if (ignoreUrlMatcher.match(url, requestPath)) {
return true;
}
}
return false;
}
private String getRequestPath(HttpServletRequest request) {
String url = request.getServletPath();
String pathInfo = request.getPathInfo();
if (pathInfo != null) {
url = org.springframework.util.StringUtils.hasLength(url) ? url + pathInfo : pathInfo;
}
return url;
}
}
2.4 将拦截器注入
注意设置优先等级,否则执行顺序会有问题,导致获取不到设备信息。
@Configuration
public class FilterConfig {
@Bean
public AuthFilter AuthFilter() {
return new AuthFilter();
}
@Bean
public DeviceResolverRequestFilter deviceResolverRequestFilter(){
return new DeviceResolverRequestFilter();
}
@Bean
public FilterRegistrationBean<AuthFilter> authFilterRegistration() {
FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(AuthFilter());
// registration.addUrlPatterns(AppConst.APP_URL_PREFIX+"/*");
registration.setOrder(1);
return registration;
}
@Bean
public FilterRegistrationBean<DeviceResolverRequestFilter> deviceResolverRequestFilterRegistration() {
FilterRegistrationBean<DeviceResolverRequestFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(deviceResolverRequestFilter());
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registration;
}
}
2.5 UserUtil直接在请求中获取对应参数的工具类。包含直接的设备判定。
public class UserUtil {
private UserUtil() {
}
// 全用户
public static SysUser getUser() {
return UserAccountHolder.getUser();
}
// officeId
public static String getOfficeId() {
SysUser user = UserAccountHolder.getUser();
if (Objects.isNull(user)) {
throw new BaseException(MessageEnum.ERROR_1010);
}
return user.getOfficeId();
}
// getUserId
public static String getUserId() {
SysUser user = UserAccountHolder.getUser();
if (Objects.isNull(user)) {
throw new BaseException(MessageEnum.ERROR_1010);
}
return user.getId();
}
// getToken
public static String getToken() {
SysUser user = UserAccountHolder.getUser();
if (Objects.isNull(user)) {
throw new BaseException(MessageEnum.ERROR_1010);
}
return user.getSecurityKey();
}
// getToken
public static String getPassword() {
SysUser user = UserAccountHolder.getUser();
if (Objects.isNull(user)) {
throw new BaseException(MessageEnum.ERROR_1010);
}
return user.getPassword();
}
// 修改用户
public static void setUser(SysUser sysUser) {
if (Objects.isNull(sysUser)) {
throw new BaseException(MessageEnum.ERROR_1010);
}
UserAccountHolder.setUser(sysUser);
}
//获取isMobile
public static boolean isMobile() {
SysUser user = UserAccountHolder.getUser();
if (Objects.isNull(user)) {
throw new BaseException(MessageEnum.ERROR_1010);
}
return user.getDevice().isMobile();
}
//获取isNormal
public static boolean isNormal() {
SysUser user = UserAccountHolder.getUser();
if (Objects.isNull(user)) {
throw new BaseException(MessageEnum.ERROR_1010);
}
return user.getDevice().isNormal();
}
//获取isTablet
public static boolean isTablet() {
SysUser user = UserAccountHolder.getUser();
if (Objects.isNull(user)) {
throw new BaseException(MessageEnum.ERROR_1010);
}
return user.getDevice().isTablet();
}
}
2.6 controller层应用 直接通过UserUtil就可直接获取信息,不再用添加HttpServletRequest,来再获取信息。当然也可以应用到对应的Service层都是可以直接获取的,同时设备信息也可以直接判定来不同实现。
/**
* 获取用户全部个人信息
*
* @return 用户个人信息
*/
@GetMapping("/user")
@ApiOperation(value = "1.0.4 查询个人全部信息接口", httpMethod = "GET")
public ResultVo user() {
SysUser sysUser = authService.user(UserUtil.getToken());
return new ResultVo<>().setData(sysUser);
}
3总结
对于相对于简单的权限管理这个足够用了。主要流程:1.注入设备获取相关的Bean.2.创建拦截器,获取token.3.对拦截器进行注入Bean,设置优先级。4.通过本地线程直接使用。