栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据

【SpringCloud】单点系统结合数据库和Feign

大数据 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【SpringCloud】单点系统结合数据库和Feign

一,业务描述 1.增加数据库访问

第一:登录用户信息来自数据库(用户自身信息以及用户对应的权限信息)
第二:将上传的文件信息写入到数据库
第三:将登录操作,文件上传操作的操作日志写入到数据库.

2.增加服务之间的调用

第一:认证服务调用系统服务(获取用户以及用户权限)
第二:认证服务与资源服务都调用系统服务(将日志传递给系统服务,进行数据的持久化)

二,系统服务设计及实现 1.业务描述

系统服务sca-system工程用于提供其它服务需要的基础数据,例如用户信息,日志信息的记录等,其关键表设计例如:

2.服务设计

3.工程结构

4.数据初始化

将事先准备好的jt-sso.sql文件在导入数据库,
可以使用命令:source F:/resource/jt-sso.sql
也可以使用可视化工具导入

5.创建系统工程

创建sca-system工程,此工程作为02-sca-files的子工程进行业务实现,例如:

6.添加项目核心依赖

        
        
            mysql
            mysql-connector-java
        
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.4.2
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-config
        
    
7.创建项目配置文件

在项目中添加bootstrap.yml文件,其内容如下

server:
  port: 8061
spring:
  application:
    name: sca-system
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        server-addr: localhost:8848
        file-extension: yml
  datasource:
    url: jdbc:mysql:///jt-sso?serverTimezone=Asia/Shanghai&characterEncoding=utf8
    username: root
    password: root
8.创建项目启动及测试类

第一步:在项目中添加启动类,例如:

package com.jt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SystemApplication {
    public static void main(String[] args) {
        SpringApplication.run(SystemApplication.class,args);
    }
}

第二步:在项目中添加单元测试类,测试数据库连接,例如:

package com.jt;

import com.jt.system.dao.UserMapper;
import com.jt.system.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;


@SpringBootTest
public class DataSourceTests {
    
    @Autowired
    private DataSource dataSource; //HikariProxyConnection
    @Test
    void testGetConnection() throws SQLException {
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
    }
}

测试结果:

9.Pojo对象逻辑实现

添加项目User对象,用于封装用户信息。

package com.jt.system.pojo;
import lombok.Data;
import java.io.Serializable;


@Data
public class User implements Serializable {
    private static final long serialVersionUID = 4831304712151465443L;
    private Long id;
    private String username;
    private String password;
    private String status;
}

这里的serialVersionUID的自动生成可以如下操作:
File–settings

鼠标放向类名 Alt+回车

10.Dao对象逻辑实现

第一步:创建UserMapper接口,并定义基于用户名查询用户信息,基于用户id查询用户权限信息的方法,代码如下:

package com.jt.system.dao;

import com.baomidou.mybatisplus.core.mapper.baseMapper;
import com.jt.system.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserMapper extends baseMapper {
    
    @Select("select id,username,password,status " +
            "from tb_users " +
            "where username=#{username}")
    User selectUserByUsername(String username);

    
    @Select("select distinct m.permission " +
            "from tb_user_roles ur join tb_role_menus rm on ur.role_id=rm.role_id" +
            "     join tb_menus m on rm.menu_id=m.id " +
            "where ur.user_id=#{userId}")
    List selectUserPermissions(Long userId);

}

第二步:在DataSourceTests类,对业务方法做单元测试,例如:

package com.jt;

import com.jt.system.dao.UserMapper;
import com.jt.system.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;


@SpringBootTest
public class DataSourceTests {
    
    @Autowired
    private DataSource dataSource; //HikariProxyConnection
    @Autowired
    private UserMapper userMapper;
    @Test
    void testGetConnection() throws SQLException {
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
    }
    @Test
    void testSelectUserByUsername() {
        User admin = userMapper.selectUserByUsername("admin");
        System.out.println(admin);
    }
    @Test
    void testSelectUserPermissions() {
        List permissions = userMapper.selectUserPermissions(1l);
        System.out.println(permissions);
    }
}
三,认证服务工程中Feign应用 1.业务描述

在认证sca-auth工程中,我们通过调用sca-system服务获取登录用户信息,用户权限信息.

2.添加Feign依赖

在sca-auth工程中添加如下依赖,例如:

  
        org.springframework.cloud
        spring-cloud-starter-openfeign
  
3.Pojo对象逻辑实现
package com.jt.auth.pojo;
import lombok.Data;
import java.io.Serializable;
@Data
public class User implements Serializable {
    private static final long serialVersionUID = 4831304712151465443L;
    private Long id;
    private String username;
    private String password;
    private String status;
}

4.Feign接口逻辑实现

创建Feign接口,基于feign实现远程调用逻辑,例如:

package com.jt.auth.feign;
import com.jt.auth.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.List;

@FeignClient(name = "sca-system",contextId = "remoteUserService")
public interface RemoteUserService {
       
       @GetMapping("/user/login/{username}")
       User selectUserByUsername(
               @PathVariable("username") String username);

       
       @GetMapping("/user/permission/{userId}")
       List selectUserPermissions(
               @PathVariable("userId")Long userId);
}

说明,feign接口定义后,需要在sca-auth启动类上添加@EnableFeignClients注解.

5.调用Feign接口逻辑

在sca-auth工程中的UserDetailServiceImpl中添加对feign接口的调用,例如:

package com.jt.auth.service;

import com.jt.auth.feign.RemoteUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;


@Slf4j
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
    @Autowired
    private RemoteUserService remoteUserService;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //基于feign方式获取远程数据并封装
        //1.基于用户名获取用户信息
        com.jt.auth.pojo.User user =
                remoteUserService.selectUserByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        //2.基于用于id查询用户权限
        List permissions = remoteUserService.selectUserPermissions(user.getId());
        log.info("permissions {}",permissions);
        //对查询结果进行封装并返回
        return new User(username,
                user.getPassword(),
                AuthorityUtils.createAuthorityList(permissions.toArray(new String[]{})));
    }
}
6.启动服务进行访问测试

启动sca-auth,sca-resource,sca-resource-gateway,sca-system,sca-resource-ui工程,然后从登录开始进行测试.
我们数据库中的信息是 用户名:user 密码:123456

7.难点分析

首先根据我们传统的登录方法,我们一般是会把前端页面的密码拿出来和数据库查询的密码进行比较,或者直接将前端用户和密码作为条件查询数据库,而这里只是根据用户名查询数据库,直接将数据库查询到的内容封装成类,并没有有校验密码的过程,这个我也想了好久,最后还是通过大佬的断点调试的方法,知道了密码的校验是在底层实现了,是在ProviderManager中进行了校验。
首先在认证配置中,设置用密码校验

而另一个中会设置认证管理

看一份流程图:

用户输入用户名和密码,即调用ProviderManger方法,该方法再调用DaoAuthentionProvider获取用来校验的数据,DaoAuthentionProvider再调用UserDetailsServiceImpl从数据库中根据用户名获取用户信息,然后将数据传给DaoAuthentionProvider,DaoAuthentionProvider再将数据传给ProviderManger,在其中先进行“gateway-client”的验证,然后再进行用户的密码校验。

同时在断点过程中,发现了DefaultAuthenticationEventPublisher类,处理认证信息的类,因次顺手写了个简单继承子类

package com.jt.auth.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;


@Slf4j
@Component
public class SSOAuthListener extends DefaultAuthenticationEventPublisher {
    @Override
    public void publishAuthenticationSuccess(Authentication authentication) {
        super.publishAuthenticationSuccess(authentication);
        UserDetails principal = (UserDetails) authentication.getPrincipal();
        log.info("{} login success {}",principal, LocalDateTime.now());
    }

    @Override
    public void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication) {
        super.publishAuthenticationFailure(exception, authentication);
        log.info("login failure {} {}",LocalDateTime.now(),exception.getMessage());
    }
}

我设置的是当我们登录成功后,会在后台打印信息,结果如下

所以我们需要将用户登录日志传入数据库的话,可以使用Feign在此处调用system中的方法,实现日志的入库。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/278348.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号