用户登录权限验证
一, 登录
引导类:
@SpringBootApplication
//如果默认手动指定扫描的包 默认扫描包的规则则失效
@ComponentScan(
basePackages =
{
“..web”,
“..system”,
}
)
@MapperScan(“..system.mappers”)
public class SystemApplication {
public static void main(String[] args) {
SpringApplication.run(SystemApplication.class, args);
}
}
Controller层
@RestController
public class LoginController {
@Autowired
private UserService userService;
@PostMapping("/login")
public ResponseResult login(@RequestBody LoginDto dto) {
return userService.login(dto);
}
}
ServiceImpl层
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
//用户登录
@Override
public ResponseResult login(LoginDto dto) {
//1. 验证请求参数 做非空判断
String phone = dto.getUsername();//登录手机号
String password = dto.getPassword();//登录密码
String utype = dto.getUtype();//登录手机号
if (StringUtils.isEmpty(password) ||
StringUtils.isEmpty(phone)||
StringUtils.isEmpty(utype)) {
throw new BusinessException(ErrorCode.LOGINERROR);//用户名或者密码错误
}
//2.根据根据请求的参数 从库里查询用户对象
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getPhone, phone);//登录手机号
wrapper.eq(User::getUtype, utype);//登录手机号
User user = userMapper.selectOne(wrapper);
//3 判断 用户是否存在
//3-1用户不存在 抛错误提示
if (StringUtils.isEmpty(user)) {
throw new BusinessException(ErrorCode.LOGINERROR);
}
//3-2 用户存在 则对传入的密码进行md5加密 并且与库里的进行对比
String mdPassword = DigestUtil.md5Hex(password);
if (!mdPassword.equals(user.getPassword())) {
throw new BusinessException(ErrorCode.LOGINERROR);
}
//4.密码比对成功 ,生成token字符串
//4-1 构建map集合
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("userId", user.getId());//用户名
hashMap.put("companyId", user.getCompanyId());//机构Id
hashMap.put("companyName", user.getCompanyName());//机构名
//4-2.存入jwt ,并且设置有效期(这里设置24小时)
String token = JwtUtils.createToken(hashMap, 60 * 24);
//返回结果
LoginVo vo = new LoginVo();
vo.setAccess_token(token);
vo.setUsername(user.getName());
return ResponseResult.okResult(vo);
}
}
二,搭建微服务网关
网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等。学成在线也是通过网关介入所有请求,进行路由转发
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xc-framework-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
## 路由配置
server:
port: 60010
spring:
application:
name: xc-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.136.150:8848 #注册中心nacos地址
gateway:
globalcors:
cors-configurations:
'[/]': # 匹配所有请求
allowedOrigins: “*” #跨域处理 允许所有的域
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
- id: content
uri: lb://xc-content-service
predicates:
- Path=/content/
filters:
- StripPrefix=1
- id: system
uri: lb://xc-system-service
predicates:
- Path=/system/**
filters:
- StripPrefix=1
- id: media
uri: lb://xc-media-service
predicates:
- Path=/media/**
filters:
- StripPrefix=1
- id: auth
uri: lb://xc-system-service
predicates:
- Path=/auth/**
filters:
- StripPrefix=1
- id: basic
uri: lb://xc-basic-service
predicates:
- Path=/basic/**
filters:
- StripPrefix=1
- id: order
uri: lb://xc-order-service
predicates:
- Path=/order/**
filters:
- StripPrefix=1
- id: teaching
uri: lb://xc-teaching-service
predicates:
- Path=/teaching/**
filters:
- StripPrefix=1
- id: search
uri: lb://xc-search-service
predicates:
- Path=/search/**
filters:
- StripPrefix=1
- id: learning
uri: lb://xc-learning-service
predicates:
- Path=/learning/**
filters:
- StripPrefix=1
logging:
level:
com.alibaba.nacos.client.*: WARN
引导类:
@SpringBootApplication
public class GatewayApplicaton {
public static void main(String[] args) {
SpringApplication.run(GatewayApplicaton.class, args);
}
}
三,统一Token处理
登录验证:
网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等。
执行流程:
1. 请求发送到网关,在网关层进行token的验证和解析
2. 网关转发到微服务,这是携带新的请求头payload
3. 微服务拦截器获取payload转化java对象,存入Threadlocal
4. controller及后续方法,直接从当前线程获取
四,网关登录校验
GlobalFilter 全局过滤器,不需要在配置文件中配置,系统初始化时加载,并作用在每个路由上。
- 对于不需要鉴权的请求放行
- 获取请求头中的Authorization请求头
- 校验token,如果检验失败则响应401(未登录)
- 为了方便后续的操作,在网关中解析token。将数据转为json向后续微服务传递
五,在网关模块添加全局过滤器
全局过滤器详见:https://blog.csdn.net/apple_69693064/article/details/127020499
六,统一token解析
1.编写拦截器
@Component
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {
//1.进入controller方法之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String payload = request.getHeader("payload");
if (StringUtils.isEmpty(payload)) {
return true;
}
//转换成AuthInfo对象
String json = URLDecoder.decode(payload, "UTF-8");
log.info("json"+json);
AuthInfo info = JSON.parseObject(json, AuthInfo.class);
log.info("json"+json);
AuthInfoHolder.setAuthInfo(info);//存入ThreadLocal线程中
return true;//放行请求
}
//2.Controller方法之后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
//3.离开controller方法之后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
AuthInfoHolder.remove();
}
}
1.配置拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TokenInterceptor()) // 添加拦截器
.addPathPatterns("/**"); // 添加拦截的路径
}
}
七,ThreadLocal工具类
详情见:https://blog.csdn.net/apple_69693064/article/details/126916334
八,全局异常处理
详情见:https://blog.csdn.net/apple_69693064/article/details/127020516
注意:在每个微服务中,都会使用统一异常处理和过滤器的相关代码逻辑。为了尽可能的复用代码,需要将公共的逻辑抽取到一个合适的公共模块下