第一:登录用户信息来自数据库(用户自身信息以及用户对应的权限信息)
第二:将上传的文件信息写入到数据库
第三:将登录操作,文件上传操作的操作日志写入到数据库.
第一:认证服务调用系统服务(获取用户以及用户权限)
第二:认证服务与资源服务都调用系统服务(将日志传递给系统服务,进行数据的持久化)
系统服务sca-system工程用于提供其它服务需要的基础数据,例如用户信息,日志信息的记录等,其关键表设计例如:
将事先准备好的jt-sso.sql文件在导入数据库,
可以使用命令:source F:/resource/jt-sso.sql
也可以使用可视化工具导入
创建sca-system工程,此工程作为02-sca-files的子工程进行业务实现,例如:
7.创建项目配置文件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
在项目中添加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);
}
}
测试结果:
添加项目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+回车
第一步:创建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工程中添加如下依赖,例如:
3.Pojo对象逻辑实现org.springframework.cloud spring-cloud-starter-openfeign
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
首先根据我们传统的登录方法,我们一般是会把前端页面的密码拿出来和数据库查询的密码进行比较,或者直接将前端用户和密码作为条件查询数据库,而这里只是根据用户名查询数据库,直接将数据库查询到的内容封装成类,并没有有校验密码的过程,这个我也想了好久,最后还是通过大佬的断点调试的方法,知道了密码的校验是在底层实现了,是在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中的方法,实现日志的入库。



