SpringSecurity在微服务中的应用
前述
源代码已经上传到 Gitee,对应项目为
security-cloud
本文在security整合JWT 基础上进行修改
代码中使用的
redis
的有关配置请参考 SpringBoot整合Redis
SpringCloud几个依赖关系
依赖 | 版本号 |
---|---|
spring-boot | 2.7.2 |
spring-cloud | 2021.0.3 |
spring-cloud-alibaba | 2021.0.1.0 |
nacos-client | 2.1.0 |
openfeign | 3.1.3 |
目录结构
父POM
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>security-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>security-cloud</name>
<description>security-cloud:security微服务下的使用</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.7.2</spring-boot.version>
<spring-cloud.version>2021.0.3</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version>
<alibaba.nacos.version>2.1.0</alibaba.nacos.version>
<cloud-openfeign.version>3.1.3</cloud-openfeign.version>
<mybatis-plus-boot-starter.version>3.5.1</mybatis-plus-boot-starter.version>
<druid-spring-boot-starter.version>1.2.8</druid-spring-boot-starter.version>
<jwt.version>0.9.1</jwt.version>
<hutool-all.version>5.8.4</hutool-all.version>
<commons-lang3.version>3.12.0</commons-lang3.version>
<fastjson2.version>2.0.9</fastjson2.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- SpringBoot 依赖配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringCloud 微服务 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring-cloud-alibaba-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Alibaba Nacos 配置 -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${alibaba.nacos.version}</version>
</dependency>
<!-- openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${cloud-openfeign.version}</version>
</dependency>
<!--mybatis-plus 持久层-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<!--JSON解析-->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson2.version}</version>
</dependency>
<!--java工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-all.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- bootstrap 启动器:解决Cloud高版本下不先加载bootstrap.properties问题
see github issue:https://github.com/alibaba/spring-cloud-alibaba/issues/1994
-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
<modules>
<module>security-common</module>
<module>security-modules</module>
<module>security-gateway</module>
</modules>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
security-common-security模块
退出处理器
/**
* @version 1.0.0
* @className: LogoutSuccessHandlerImpl
* @description: 退出处理器
* @author: LiJunYi
* @create: 2022/7/26 8:34
*/
@Configuration
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
{
@Resource
private TokenManager tokenManager;
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication e) throws IOException {
LoginUser loginUser = tokenManager.getLoginUser(request);
if(ObjectUtil.isNotNull(loginUser))
{
//移除
tokenManager.removeToken(loginUser.getToken());
}
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success("退出成功")));
}
}
security-gateway网关模块
依赖引入
注意事项: spring-cloud-starter-alibaba-nacos-config
模块移除了 spring-cloud-starter-bootstrap
依赖,如果你想以旧版的方式使用,你需要手动加上该依赖
详细见:Spring Cloud Alibaba 2021.0.1.0 升级指南
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>security-cloud</artifactId>
<groupId>org.example</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>security-gateway</artifactId>
<dependencies>
<!--引入公共模块-->
<dependency>
<groupId>org.example</groupId>
<artifactId>security-common-base</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.2</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
bootstrap.yml
server:
port: 9527
spring:
application:
name: security-gateway
profiles:
active: dev
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
- id: security-system
uri: lb://security-system
predicates:
- Path=/sys/**
security-system业务模块
依赖引入
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>security-modules</artifactId>
<groupId>org.example</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>security-system</artifactId>
<dependencies>
<!--引入公共模块-->
<dependency>
<groupId>org.example</groupId>
<artifactId>security-common-base</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--引入security模块-->
<dependency>
<groupId>org.example</groupId>
<artifactId>security-common-security</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--服务调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok用来简化实体类:需要安装lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--JSON解析-->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!--java工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8009
spring:
application:
name: security-system
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
redis:
host: localhost
port: 6379
database: 0
password:
timeout: 10s
lettuce:
pool:
min-idle: 0
max-idle: 8
max-active: 8
max-wait: -1ms
datasource:
url: jdbc:mysql://127.0.0.1:3306/security-simple?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: admin
driver-class-name: com.mysql.cj.jdbc.Driver
#mybatis-plus
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
management:
endpoints:
web:
exposure:
exclude: '*'
MyUserDetailsServiceImpl
/**
* @version 1.0.0
* @className: MyUserDetailsServiceImpl
* @description: security具体登录逻辑
* @author: LiJunYi
* @create: 2022/7/26 9:11
*/
@Service
public class MyUserDetailsServiceImpl implements UserDetailsService
{
private static final Logger log = LoggerFactory.getLogger(MyUserDetailsServiceImpl.class);
private final ISysUserService userService;
private final SysPermissionService permissionService;
/**
* 构造器注入
*
* @param userService 用户服务
* @param permissionService 许可服务
*/
public MyUserDetailsServiceImpl(ISysUserService userService, SysPermissionService permissionService)
{
this.userService = userService;
this.permissionService = permissionService;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
SysUser user = userService.getByUsername(username);
if (ObjectUtil.isNull(user))
{
log.info("登录用户:{} 不存在.", username);
throw new ServiceException("登录用户:" + username + " 不存在");
}
// 获取角色
List<SysRole> roles = permissionService.getRolesByUserId(user);
user.setRoles(roles);
return createLoginUser(user);
}
public UserDetails createLoginUser(SysUser user)
{
return new LoginUser(Convert.toLong(user.getId()), 1000L, user, permissionService.getMenuPermission(user));
}
}
登录处理类
/**
* @version 1.0.0
* @className: SysLoginService
* @description: 登录业务
* @author: LiJunYi
* @create: 2022/7/27 12:53
*/
@Component
public class SysLoginService
{
@Autowired
private TokenManager tokenManager;
@Resource
private AuthenticationManager authenticationManager;
@Autowired
private RedisCache redisCache;
@Autowired
private ISysUserService userService;
/**
* 登录验证
*
* @param username 用户名
* @param password 密码
* @return 结果
*/
public String login(String username, String password)
{
// 用户验证
Authentication authentication;
try
{
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(username, password));
}
catch (Exception e)
{
if (e instanceof BadCredentialsException)
{
throw new ServiceException("用户名密码错误");
}
else
{
throw new ServiceException(e.getMessage());
}
}
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
// 生成token
return tokenManager.createToken(loginUser);
}
}
启动服务
1、分别启动我们的Redis以及Nacos
2、启动业务模块以及网关模块
3、访问:http://localhost:8848/nacos/,观察Nacos控制台服务列表
测试效果图
最后
目前这个示例只是 SpringSecurity
在微服务中的简单使用,而且鉴权等也没有放在网关上进行,而是放在了业务模块上。
后续会进一步修改,将鉴权放在网关上。然后就是会加入 Spring Security Oauth2
来实现服务间的鉴权。
如果示例中有什么不对的地方,希望大家多多指正,有修改才有进步!