設(shè)置通用父工程依賴
在微服務(wù)構(gòu)建中,我們一般用一個父工程來通知管理依賴的各種版本號信息。父工程pom文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<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>com.zjq</groupId>
<artifactId>oauth2-demo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>commons</module>
<module>ms-gateway</module>
<module>ms-oauth2-server</module>
<module>ms-registry</module>
</modules>
<!-- 可以集中定義依賴資源的版本信息 -->
<properties>
<spring-boot-version>2.3.7.RELEASE</spring-boot-version>
<spring-cloud-version>Hoxton.SR9</spring-cloud-version>
<lombok-version>1.18.16</lombok-version>
<commons-lang-version>3.11</commons-lang-version>
<mybatis-starter-version>2.1.3</mybatis-starter-version>
<mysql-version>8.0.22</mysql-version>
<swagger-starter-version>2.1.5-RELEASE</swagger-starter-version>
<hutool-version>5.4.7</hutool-version>
<guava-version>20.0</guava-version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 集中定義依賴,不引入 -->
<dependencyManagement>
<dependencies>
<!-- spring boot 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud 依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- lombok 依賴 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
</dependency>
<!-- common-lang3 依賴 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang-version}</version>
</dependency>
<!-- mybatis 依賴 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-starter-version}</version>
</dependency>
<!-- swagger 依賴 -->
<dependency>
<groupId>com.battcn</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>${swagger-starter-version}</version>
</dependency>
<!-- mysql 依賴 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-version}</version>
</dependency>
<!-- hutool 依賴 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-version}</version>
</dependency>
<!-- guava 依賴 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava-version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 集中定義項目所需插件 -->
<build>
<pluginManagement>
<plugins>
<!-- spring boot maven 項目打包插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
構(gòu)建eureka注冊中心
在SpringCloud微服務(wù)體系中服務(wù)注冊中心是一個必要的存在,通過注冊中心提供服務(wù)的注冊和發(fā)現(xiàn)。具體細節(jié)可以查看我之前的博客,這里不再贅述。我們開始構(gòu)建一個eureka注冊中心,對應(yīng)的yml配置文件如下:
server:
port: 8080
spring:
application:
# 應(yīng)用名稱
name: ms-registry
# 配置 Eureka Server 注冊中心
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8080/eureka/
logging:
pattern:
console: '%d{HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n'
對應(yīng)的項目啟動類代碼如下:
package com.zjq.msregistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* 注冊中心
* @author zjq
*/
//啟動 eureka注冊中心服務(wù)端相關(guān)組件
@EnableEurekaServer
@SpringBootApplication
public class MsRegistryApplication {
public static void main(String[] args) {
SpringApplication.run(MsRegistryApplication.class, args);
}
}
至此,一個單體的服務(wù)注冊中心搭建完成。
構(gòu)建認證授權(quán)服務(wù)
上文我們已經(jīng)完成了注冊中心的搭建,接下來我們開始搭建認證授權(quán)中心。
配置文件設(shè)置
我們同樣在父工程下面新建一個子工程,作為認證授權(quán)中心的微服務(wù)。對應(yīng)的yml文件和pom文件配置如下:
application.yml
server:
port: 8082 # 端口
spring:
application:
name: ms-oauth2-server # 應(yīng)用名
# 數(shù)據(jù)庫
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/oauth2?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false
# Redis
redis:
port: 6379
host: localhost
timeout: 3000
database: 1
password: 123456
# swagger
swagger:
base-package: com.zjq.oauth2
title: 認證服務(wù)API接口文檔
# Oauth2
client:
oauth2:
client-id: appId # 客戶端標識 ID
secret: 123456 # 客戶端安全碼
# 授權(quán)類型
grant_types:
- password
- refresh_token
# token 有效時間,單位秒
token-validity-time: 3600
refresh-token-validity-time: 3600
# 客戶端訪問范圍
scopes:
- api
- all
# 配置 Eureka Server 注冊中心
eureka:
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${server.port}
client:
service-url:
defaultZone: http://localhost:8080/eureka/
# Mybatis
mybatis:
configuration:
map-underscore-to-camel-case: true # 開啟駝峰映射
# 指標監(jiān)控健康檢查
management:
endpoints:
web:
exposure:
include: "*" # 暴露的端點
logging:
pattern:
console: '%d{HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n'
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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>oauth2-demo</artifactId>
<groupId>com.zjq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ms-oauth2-server</artifactId>
<dependencies>
<!-- eureka client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- spring web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring data redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- spring cloud security -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<!-- spring cloud oauth2 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<!-- commons 公共項目 -->
<dependency>
<groupId>com.zjq</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 自定義的元數(shù)據(jù)依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
Security配置類
我們開始搭建Spring Security相關(guān)的配置類,具體配置類代碼如下:
package com.zjq.oauth2.server.config;
import cn.hutool.crypto.digest.DigestUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import javax.annotation.Resource;
/**
* Security 配置類
* @author zjq
*/
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
// 注入 Redis 連接工廠
@Resource
private RedisConnectionFactory redisConnectionFactory;
/**
* 初始化 RedisTokenStore 用于將 token 存儲至 Redis
* @return
*/
@Bean
public RedisTokenStore redisTokenStore() {
RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);
redisTokenStore.setPrefix("TOKEN:"); // 設(shè)置key的層級前綴,方便查詢
return redisTokenStore;
}
// 初始化密碼編碼器,用 MD5 加密密碼
@Bean
public PasswordEncoder passwordEncoder() {
return new PasswordEncoder() {
/**
* 加密
* @param rawPassword 原始密碼
* @return
*/
@Override
public String encode(CharSequence rawPassword) {
return DigestUtil.md5Hex(rawPassword.toString());
}
/**
* 校驗密碼
* @param rawPassword 原始密碼
* @param encodedPassword 加密密碼
* @return
*/
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return DigestUtil.md5Hex(rawPassword.toString()).equals(encodedPassword);
}
};
}
// 初始化認證管理對象
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
// 放行和認證規(guī)則
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
// 放行的請求
.antMatchers("/oauth/**", "/actuator/**").permitAll()
.and()
.authorizeRequests()
// 其他請求必須認證才能訪問
.anyRequest().authenticated();
}
}
Security配置類主要完成以下配置:
- 注入 Redis 連接工廠
- 初始化 RedisTokenStore 用于將 token 存儲至 Redis
- 初始化密碼編碼器,用 MD5 加密密碼
- 初始化認證管理對象
- 設(shè)置放行和認證規(guī)則
授權(quán)服務(wù)配置類
配置完了security配置類后,我們開始編寫授權(quán)服務(wù)配置類,授權(quán)服務(wù)配置類需要繼承AuthorizationServerConfigurerAdapter
并重寫對應(yīng)的方法,tips:idea子類重寫父類快捷鍵是Ctrl+O
,重寫后的授權(quán)服務(wù)配置類如下:
package com.zjq.oauth2.server.config;
import com.zjq.commons.model.domain.SignInIdentity;
import com.zjq.oauth2.server.service.UserService;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import javax.annotation.Resource;
import java.util.LinkedHashMap;
/**
* 授權(quán)服務(wù)配置類
* @author zjq
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
// RedisTokenSore
@Resource
private RedisTokenStore redisTokenStore;
// 認證管理對象
@Resource
private AuthenticationManager authenticationManager;
// 密碼編碼器
@Resource
private PasswordEncoder passwordEncoder;
// 客戶端配置類
@Resource
private ClientOAuth2DataConfiguration clientOAuth2DataConfiguration;
// 登錄校驗
@Resource
private UserService userService;
/**
* 配置令牌端點安全約束
*
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
// 允許訪問 token 的公鑰,默認 /oauth/token_key 是受保護的
security.tokenKeyAccess("permitAll()")
// 允許檢查 token 的狀態(tài),默認 /oauth/check_token 是受保護的
.checkTokenAccess("permitAll()");
}
/**
* 客戶端配置 - 授權(quán)模型
*
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient(clientOAuth2DataConfiguration.getClientId()) // 客戶端標識 ID
.secret(passwordEncoder.encode(clientOAuth2DataConfiguration.getSecret())) // 客戶端安全碼
.authorizedGrantTypes(clientOAuth2DataConfiguration.getGrantTypes()) // 授權(quán)類型
.accessTokenValiditySeconds(clientOAuth2DataConfiguration.getTokenValidityTime()) // token 有效期
.refreshTokenValiditySeconds(clientOAuth2DataConfiguration.getRefreshTokenValidityTime()) // 刷新 token 的有效期
.scopes(clientOAuth2DataConfiguration.getScopes()); // 客戶端訪問范圍
}
/**
* 配置授權(quán)以及令牌的訪問端點和令牌服務(wù)
*
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 認證器
endpoints.authenticationManager(authenticationManager)
// 具體登錄的方法
.userDetailsService(userService)
// token 存儲的方式:Redis
.tokenStore(redisTokenStore);
}
}
上面用到的客戶端配置類如下:
package com.zjq.oauth2.server.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 客戶端配置類
* @author zjq
*/
@Component
@ConfigurationProperties(prefix = "client.oauth2")
@Data
public class ClientOAuth2DataConfiguration {
// 客戶端標識 ID
private String clientId;
// 客戶端安全碼
private String secret;
// 授權(quán)類型
private String[] grantTypes;
// token有效期
private int tokenValidityTime;
/**
* refresh-token有效期
*/
private int refreshTokenValidityTime;
/**
* 客戶端訪問范圍
*/
private String[] scopes;
}
具體登錄的方法實現(xiàn):
登錄實現(xiàn)
package com.zjq.oauth2.server.service;
import com.zjq.commons.model.domain.SignInIdentity;
import com.zjq.commons.model.pojo.Users;
import com.zjq.commons.utils.AssertUtil;
import com.zjq.oauth2.server.mapper.UsersMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 登錄校驗
* @author zjq
*/
@Service
public class UserService implements UserDetailsService {
@Resource
private UsersMapper usersMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
AssertUtil.isNotEmpty(username, "請輸入用戶名");
Users users = usersMapper.selectByAccountInfo(username);
if (users == null) {
throw new UsernameNotFoundException("用戶名或密碼錯誤,請重新輸入");
}
// 初始化登錄認證對象
SignInIdentity signInIdentity = new SignInIdentity();
// 拷貝屬性
BeanUtils.copyProperties(users, signInIdentity);
return signInIdentity;
}
}
UsersMapper:
package com.zjq.oauth2.server.mapper;
import com.zjq.commons.model.pojo.Users;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* 用戶 Mapper
* @author zjq
*/
public interface UsersMapper {
/**
*
* 根據(jù)用戶名 or 手機號 or 郵箱查詢用戶信息
*
* @param account
* @return
*/
@Select("select id, username, nickname, phone, email, " +
"password, avatar_url, roles, is_valid from t_users where " +
"(username = #{account} or phone = #{account} or email = #{account})")
Users selectByAccountInfo(@Param("account") String account);
}
用戶實體:
package com.zjq.commons.model.pojo;
import com.zjq.commons.model.base.BaseModel;
import lombok.Getter;
import lombok.Setter;
/**
* 用戶實體類
*
* @Author zjq
* @Date 2022/10/12
*/
@Getter
@Setter
public class Users extends BaseModel {
// 主鍵
private Integer id;
// 用戶名
private String username;
// 昵稱
private String nickname;
// 密碼
private String password;
// 手機號
private String phone;
// 郵箱
private String email;
// 頭像
private String avatarUrl;
// 角色
private String roles;
}
package com.zjq.commons.model.base;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
/**
* 實體對象公共屬性
*
* @Author zjq
* @Date 2022/10/12
*/
@Getter
@Setter
public class BaseModel implements Serializable {
private Integer id;
private Date createDate;
private Date updateDate;
private int isValid;
}
到此,我們完成了認證授權(quán)服務(wù)構(gòu)建,接下來我們進行測試驗證:
測試驗證
我們啟動注冊中心和認證授權(quán)微服務(wù)。訪問注冊中心:http://localhost:8080/
可以看到認證授權(quán)服務(wù)已經(jīng)注冊到注冊中心。
接下來我們通過postman訪問請求token測試:
Authorization請求頭中配置,username和password,對應(yīng)oauth客戶端中的配置:
在body中配置請求參數(shù),發(fā)起請求后返回如下:
在Redis中我們也可以看到生成的相關(guān)token配置:
至此,我們完成了認證授權(quán)中心的初步搭建。
本文內(nèi)容到此結(jié)束了,
如有收獲歡迎點贊??收藏??關(guān)注??,您的鼓勵是我最大的動力。
如有錯誤?疑問??歡迎各位指出。
主頁:共飲一杯無的博客匯總?????文章來源:http://www.zghlxwxcb.cn/news/detail-459447.html保持熱愛,奔赴下一場山海。??????文章來源地址http://www.zghlxwxcb.cn/news/detail-459447.html
到了這里,關(guān)于SpringCloud整合spring security+ oauth2+Redis實現(xiàn)認證授權(quán)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!