文章目录 1、单点登录解决方案 2、user服务-登录接口 2.1、UserController 2.2、UserInfoServiceImpl 2.3、载荷 2.4、响应 2.5、Redis Desktop Manager 3、user服务-登录成功获取用户信息回显 3.1、UserController 3.2、UserInfoServiceImpl 3.3、响应 4、登录状态验证&状态透传分析 4.1、gateway-过滤器统一校验登录状态 4.2、登录状态透传拦截器 4.2.1、SpzxServiceAuthInterceptor 4.2.2、H5SpzxWebMvcConfigurer 4.2.3、@EnableSpzxServiceAuth 4.2.4、UserInfoServiceImpl 5、登录校验状态透传总结
1、单点登录解决方案
1.1、后端保存登录状态
1.2、token模式
2、user服务-登录接口
2.1、UserController
@Operation ( summary = "用户登录接口" ) @PostMapping ( "/login" ) public Result login ( @RequestBody UserInfo userInfo) { String token = userInfoService. login ( userInfo) ; return Result . ok ( token) ; }
2.2、UserInfoServiceImpl
@Override public String login ( UserInfo userInfo) { String username = userInfo. getUsername ( ) ; String password = userInfo. getPassword ( ) ; if ( StringUtils . isEmpty ( username) || StringUtils . isEmpty ( password) ) { throw new SpzxException ( ResultCodeEnum . LOGIN_PARAMS_ERROR , null ) ; } UserInfo dbUserInfo = this . getOne ( Wrappers . lambdaQuery ( UserInfo . class ) . eq ( UserInfo :: getUsername , username) ) ; if ( dbUserInfo == null ) { throw new SpzxException ( ResultCodeEnum . LOGIN_USERNAME_ERROR , null ) ; } if ( dbUserInfo. getStatus ( ) != 1 ) { throw new SpzxException ( ResultCodeEnum . LOGIN_USER_STATUS_ERROR , null ) ; } String encodePwd = DigestUtils . md5DigestAsHex ( ( DigestUtils . md5DigestAsHex ( password. getBytes ( ) ) + dbUserInfo. getSalt ( ) ) . getBytes ( ) ) ; if ( ! encodePwd. equals ( dbUserInfo. getPassword ( ) ) ) { throw new SpzxException ( ResultCodeEnum . LOGIN_PASSWORD_ERROR , null ) ; } String token = IdUtil . getSnowflake ( 1 , 1 ) . nextIdStr ( ) ; dbUserInfo. setPassword ( null ) ; dbUserInfo. setSalt ( null ) ; redisTemplate. opsForValue ( ) . set ( "spzx:user:login:" + token, dbUserInfo, 7 , TimeUnit . DAYS ) ; ServletRequestAttributes requestAttributes = ( ServletRequestAttributes ) RequestContextHolder . getRequestAttributes ( ) ; HttpServletRequest request = requestAttributes. getRequest ( ) ; return token; }
2.3、载荷
{ "username" : "18947628476" , "password" : "123456"
}
2.4、响应
{ "code" : 200 , "message" : "SUCCESS" , "data" : "1801188891328385024" }
2.5、Redis Desktop Manager
{ "@class" : "com.atguigu.spzx.model.entity.h5.UserInfo" , "id" : 1774759294596579329 , "createTime" : [ "java.util.Date" , "2024-04-01 19:22:44" ] , "updateTime" : [ "java.util.Date" , 1718243055000 ] , "deleted" : false , "username" : "18947628476" , "password" : null , "nickName" : "小弟" , "avatar" : "https://cdn.apifox.com/app/project-icon/builtin/16.jpg" , "sex" : null , "phone" : null , "memo" : null , "openId" : null , "unionId" : null , "lastLoginIp" : null , "lastLoginTime" : null , "status" : 1 , "salt" : null
}
3、user服务-登录成功获取用户信息回显
3.1、UserController
@Operation ( summary = "查询用户信息回显接口" ) @GetMapping ( "/auth/getCurrentUserInfo" ) public Result getCurrentUserInfo ( @RequestHeader ( value = "token" , required = false ) String token) { UserInfoVo userInfoVo = userInfoService. getCurrentUserInfo ( token) ; return Result . ok ( userInfoVo) ; }
3.2、UserInfoServiceImpl
@Override public UserInfoVo getCurrentUserInfo ( String token) { UserInfo userInfo = ( UserInfo ) redisTemplate. opsForValue ( ) . get ( "spzx:user:login:" + token) ; if ( userInfo == null ) { throw new SpzxException ( ResultCodeEnum . LOGIN_STATUS_ERROR , null ) ; } UserInfoVo userInfoVo = new UserInfoVo ( ) ; userInfoVo. setNickName ( userInfo. getNickName ( ) ) ; userInfoVo. setAvatar ( userInfo. getAvatar ( ) ) ; return userInfoVo; }
3.3、响应
{ "code" : 200 , "message" : "SUCCESS" , "data" : { "nickName" : "小弟" , "avatar" : "https://cdn.apifox.com/app/project-icon/builtin/16.jpg" }
}
4、登录状态验证&状态透传分析
4.1、gateway-过滤器统一校验登录状态
4.1.1、GlobalAuthFilter
package com. atguigu. spzx. gateway. filter ;
import com. alibaba. nacos. shaded. com. google. gson. JsonObject ;
import com. atguigu. spzx. model. result. ResultCodeEnum ;
import jakarta. annotation. Resource ;
import org. springframework. cloud. gateway. filter. GatewayFilterChain ;
import org. springframework. cloud. gateway. filter. GlobalFilter ;
import org. springframework. core. Ordered ;
import org. springframework. core. io. buffer. DataBuffer ;
import org. springframework. data. redis. core. RedisTemplate ;
import org. springframework. http. HttpStatus ;
import org. springframework. http. MediaType ;
import org. springframework. http. server. reactive. ServerHttpRequest ;
import org. springframework. http. server. reactive. ServerHttpResponse ;
import org. springframework. stereotype. Component ;
import org. springframework. util. AntPathMatcher ;
import org. springframework. util. StringUtils ;
import org. springframework. web. server. ServerWebExchange ;
import reactor. core. publisher. Mono ;
@Component
public class GlobalAuthFilter implements GlobalFilter , Ordered { @Resource private RedisTemplate redisTemplate; @Override public Mono < Void > filter ( ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange. getRequest ( ) ; String path = request. getURI ( ) . getPath ( ) ; AntPathMatcher matcher = new AntPathMatcher ( ) ; if ( ! matcher. match ( "/**/auth/**" , path) ) { return chain. filter ( exchange) ; } String token = request. getHeaders ( ) . getFirst ( "token" ) ; if ( StringUtils . isEmpty ( token) || ! redisTemplate. hasKey ( "spzx:user:login:" + token) ) { ServerHttpResponse response = exchange. getResponse ( ) ; response. setStatusCode ( HttpStatus . OK ) ; response. getHeaders ( ) . add ( "Content-Type" , MediaType . APPLICATION_JSON_UTF8_VALUE ) ; JsonObject jsonObject = new JsonObject ( ) ; jsonObject. addProperty ( "code" , ResultCodeEnum . LOGIN_STATUS_ERROR . getCode ( ) ) ; jsonObject. addProperty ( "message" , ResultCodeEnum . LOGIN_STATUS_ERROR . getMessage ( ) ) ; String json = jsonObject. toString ( ) ; DataBuffer buffer = response. bufferFactory ( ) . wrap ( json. getBytes ( ) ) ; return response. writeWith ( Mono . just ( buffer) ) ; } return chain. filter ( exchange) ; } @Override public int getOrder ( ) { return - 1 ; }
}
4.2、登录状态透传拦截器
4.2.1、SpzxServiceAuthInterceptor
package com. atguigu. spzx. common. handler. interceptor ;
import com. atguigu. spzx. model. entity. h5. UserInfo ;
import jakarta. annotation. Resource ;
import org. springframework. data. redis. core. RedisTemplate ;
import org. springframework. stereotype. Component ;
import org. springframework. web. servlet. HandlerInterceptor ;
@Component
public class SpzxServiceAuthInterceptor implements HandlerInterceptor { @Resource private RedisTemplate redisTemplate; public static ThreadLocal < UserInfo > THREAD_LOCAL = new ThreadLocal ( ) ; @Override public boolean preHandle ( jakarta. servlet. http. HttpServletRequest request, jakarta. servlet. http. HttpServletResponse response, Object handler) throws Exception { String token = request. getHeader ( "token" ) ; UserInfo userInfo = ( UserInfo ) redisTemplate. opsForValue ( ) . get ( "spzx:user:login:" + token) ; THREAD_LOCAL . set ( userInfo) ; return true ; } @Override public void afterCompletion ( jakarta. servlet. http. HttpServletRequest request, jakarta. servlet. http. HttpServletResponse response, Object handler, Exception ex) throws Exception { THREAD_LOCAL . remove ( ) ; }
}
4.2.2、H5SpzxWebMvcConfigurer
package com. atguigu. spzx. common. handler. interceptor ;
import jakarta. annotation. Resource ;
import org. springframework. context. annotation. Configuration ;
import org. springframework. web. servlet. config. annotation. InterceptorRegistry ;
import org. springframework. web. servlet. config. annotation. WebMvcConfigurer ;
@Configuration
public class H5SpzxWebMvcConfigurer implements WebMvcConfigurer { @Resource private SpzxServiceAuthInterceptor spzxServiceAuthInterceptor; @Override public void addInterceptors ( InterceptorRegistry registry) { registry. addInterceptor ( spzxServiceAuthInterceptor) . addPathPatterns ( "/**/auth/**" ) ; }
}
4.2.3、@EnableSpzxServiceAuth
package com. atguigu. spzx. common. handler. interceptor ;
import org. springframework. context. annotation. Import ;
import java. lang. annotation. * ;
@Target ( ElementType . TYPE )
@Retention ( RetentionPolicy . RUNTIME )
@Documented
@Import ( value = { SpzxServiceAuthInterceptor . class , H5SpzxWebMvcConfigurer . class } )
public @interface EnableSpzxServiceAuth {
}
4.2.4、UserInfoServiceImpl
@Override public UserInfoVo getCurrentUserInfo ( String token) { UserInfo userInfo = SpzxServiceAuthInterceptor . THREAD_LOCAL . get ( ) ; UserInfoVo userInfoVo = new UserInfoVo ( ) ; userInfoVo. setNickName ( userInfo. getNickName ( ) ) ; userInfoVo. setAvatar ( userInfo. getAvatar ( ) ) ; return userInfoVo; }
5、登录校验状态透传总结