feat(ruoyi版本同步): ruoyi-3.8.9版本同步

This commit is contained in:
zhuangpeng.li
2025-04-17 09:44:10 +08:00
parent e404cd26d4
commit ff51ea78af
62 changed files with 1814 additions and 1579 deletions

View File

@@ -46,12 +46,7 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
</dependency>
<!-- oauth2-->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>

View File

@@ -1,119 +0,0 @@
package com.fastbee.iot.oauth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import javax.sql.DataSource;
/**
* 授权服务器配置配置客户端id密钥和令牌的过期时间
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
/**
* 用来配置令牌端点(Token Endpoint)的安全约束
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.authenticationEntryPoint(new OAuth2AuthenticationEntryPoint());
}
/**
* 用来配置客户端详情服务
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(getClientDetailsService());
}
/**
* 用来配置授权authorization以及令牌token的访问端点和令牌服务(token services)。
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 查询用户、授权、分组,可以被重写
endpoints.userDetailsService(userDetailsService)
// 审批客户端的授权
.userApprovalHandler(userApprovalHandler())
// 授权审批
.approvalStore(approvalStore())
// 获取授权码
.authorizationCodeServices(new JdbcAuthorizationCodeServices(dataSource))
// 验证token
.authenticationManager(authenticationManager)
// 查询、保存、刷新token
.tokenStore(this.getJdbcTokenStore());
}
@Bean
public ApprovalStore approvalStore() {
return new JdbcApprovalStore(dataSource);
}
@Bean
public UserApprovalHandler userApprovalHandler() {
return new SpeakerApprovalHandler(getClientDetailsService(), approvalStore(), oAuth2RequestFactory());
}
@Bean
public JdbcClientDetailsService getClientDetailsService() {
JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
jdbcClientDetailsService.setPasswordEncoder(passwordEncoder());
return jdbcClientDetailsService;
}
@Bean
public OAuth2RequestFactory oAuth2RequestFactory() {
return new DefaultOAuth2RequestFactory(getClientDetailsService());
}
@Bean
public TokenStore getJdbcTokenStore(){
TokenStore tokenStore = new JdbcTokenStore(dataSource);
return tokenStore;
}
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}

View File

@@ -1,50 +0,0 @@
package com.fastbee.iot.oauth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import javax.sql.DataSource;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
TokenStore tokenStore = jdbcTokenStore();
OAuth2AuthenticationManager auth2AuthenticationManager= new OAuth2AuthenticationManager();
resources.authenticationManager(auth2AuthenticationManager);
resources.resourceId("speaker-service").tokenStore(tokenStore).stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
// 限制资源服务器只接管匹配的资源
http.requestMatchers().antMatchers("/oauth/speaker/**")
.and()
//授权的请求
.authorizeRequests()
.anyRequest().authenticated()
//关闭跨站请求防护
.and()
.csrf().disable();
}
public TokenStore jdbcTokenStore(){
TokenStore tokenStore = new JdbcTokenStore(dataSource);
return tokenStore;
}
}

View File

@@ -1,83 +0,0 @@
package com.fastbee.iot.oauth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.ApprovalStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import java.util.*;
/**
* kerwincui
*/
public class SpeakerApprovalHandler extends ApprovalStoreUserApprovalHandler {
private int approvalExpirySeconds = -1;
@Autowired
private ApprovalStore approvalStore;
public SpeakerApprovalHandler(JdbcClientDetailsService clientDetailsService, ApprovalStore approvalStore, OAuth2RequestFactory oAuth2RequestFactory) {
this.setApprovalStore(approvalStore);
this.setClientDetailsService(clientDetailsService);
this.setRequestFactory(oAuth2RequestFactory);
}
@Override
public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
// 获取授权过的范围
Set<String> requestedScopes = authorizationRequest.getScope();
Set<String> approvedScopes = new HashSet<String>();
Set<Approval> approvals = new HashSet<Approval>();
Date expiry = computeExpiry();
// 存储授权或拒绝的范围
Map<String, String> approvalParameters = authorizationRequest.getApprovalParameters();
for (String requestedScope : requestedScopes) {
String approvalParameter = OAuth2Utils.SCOPE_PREFIX + requestedScope;
String value = approvalParameters.get(approvalParameter);
value = value == null ? "" : value.toLowerCase();
if ("true".equals(value) || value.startsWith("approve")||value.equals("on")) {
approvedScopes.add(requestedScope);
approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(),
requestedScope, expiry, Approval.ApprovalStatus.APPROVED));
}
else {
approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(),
requestedScope, expiry, Approval.ApprovalStatus.DENIED));
}
}
approvalStore.addApprovals(approvals);
boolean approved;
authorizationRequest.setScope(approvedScopes);
if (approvedScopes.isEmpty() && !requestedScopes.isEmpty()) {
approved = false;
}
else {
approved = true;
}
authorizationRequest.setApproved(approved);
return authorizationRequest;
}
private Date computeExpiry() {
Calendar expiresAt = Calendar.getInstance();
// 默认一个月
if (approvalExpirySeconds == -1) {
expiresAt.add(Calendar.MONTH, 1);
}
else {
expiresAt.add(Calendar.SECOND, approvalExpirySeconds);
}
return expiresAt.getTime();
}
}

View File

@@ -1,49 +0,0 @@
package com.fastbee.iot.oauth.api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import java.security.Principal;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* kerwincui
*/
@Controller
@SessionAttributes("authorizationRequest")
public class ConfirmAccessController {
@Autowired
private JdbcClientDetailsService clientDetailsService;
@Autowired
private ApprovalStore approvalStore;
@RequestMapping("/oauth/confirm_access")
public String getAccessConfirmation(Map<String, Object> model, Principal principal ) {
AuthorizationRequest clientAuth = (AuthorizationRequest) model.remove("authorizationRequest");
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
Map<String, String> scopes = new LinkedHashMap<String, String>();
for (String scope : clientAuth.getScope()) {
scopes.put(OAuth2Utils.SCOPE_PREFIX + scope, "false");
}
for (Approval approval : approvalStore.getApprovals(principal.getName(), client.getClientId())) {
if (clientAuth.getScope().contains(approval.getScope())) {
scopes.put(OAuth2Utils.SCOPE_PREFIX + approval.getScope(),
approval.getStatus() == Approval.ApprovalStatus.APPROVED ? "true" : "false");
}
}
model.put("auth_request", clientAuth);
model.put("client", client);
model.put("scopes", scopes);
return "oauth/access_confirmation";
}
}

View File

@@ -1,55 +0,0 @@
package com.fastbee.iot.oauth.api;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.model.LoginBody;
import com.fastbee.common.utils.SecurityUtils;
import com.fastbee.framework.web.service.SysLoginService;
import com.fastbee.framework.web.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@Controller
public class LoginController {
@Autowired
private TokenStore tokenStore;
@Autowired
private SysLoginService loginService;
@Autowired
private TokenService tokenService;
@RequestMapping("/oauth/login")
public String login() {
return "oauth/login";
}
@RequestMapping("/oauth/index")
public String index() {
return "oauth/index";
}
@GetMapping("/oauth/logout")
@ResponseBody
public String logout(@RequestHeader String Authorization) {
if (!Authorization.isEmpty()){
String token=Authorization.split(" ")[1];
OAuth2AccessToken auth2AccessToken = tokenStore.readAccessToken(token);
tokenStore.removeAccessToken(auth2AccessToken);
return "SUCCESS";
}else{
return "FAIL";
}
}
}

View File

@@ -1,33 +0,0 @@
package com.fastbee.iot.oauth.api;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* kerwincui
*/
@RestController
public class SpeakerController {
@GetMapping("/oauth/speaker/get")
public JSONObject getSpeaker() {
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
JSONObject Json = new JSONObject();
Json.put("1", "1");
Json.put("2", "2");
Json.put("3", "3");
System.out.println("调用了接口get");
return Json;
}
@PostMapping("/oauth/speaker/post")
public JSONObject postSpeaker() {
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
JSONObject bookJson = new JSONObject();
bookJson.put("1", "1");
System.out.println("调用了接口post");
return bookJson;
}
}

View File

@@ -144,10 +144,10 @@ public class ToolServiceImpl implements IToolService
{
msg = "密码长度必须在5到20个字符之间";
}
else if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(sysUser)))
else if (userService.checkUserNameUnique(sysUser))
{
msg = "保存用户'" + username + "'失败,注册账号已存在";
}else if (UserConstants.NOT_UNIQUE.equals(checkPhoneUnique(phonenumber)))
}else if (checkPhoneUnique(phonenumber))
{
msg = "保存用户'" + username + "'失败,注册手机号码已存在";
}
@@ -203,10 +203,10 @@ public class ToolServiceImpl implements IToolService
{
msg = "密码长度必须在5到20个字符之间";
}
else if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(sysUser)))
else if (userService.checkUserNameUnique(sysUser))
{
msg = "保存用户'" + username + "'失败,注册账号已存在";
}else if (UserConstants.NOT_UNIQUE.equals(checkPhoneUnique(phonenumber)))
}else if (checkPhoneUnique(phonenumber))
{
msg = "保存用户'" + username + "'失败,注册手机号码已存在";
}
@@ -252,7 +252,7 @@ public class ToolServiceImpl implements IToolService
* @param phonenumber 手机号码
* @return
*/
public String checkPhoneUnique(String phonenumber)
public boolean checkPhoneUnique(String phonenumber)
{
SysUser info = userMapper.checkPhoneUnique(phonenumber);
if (StringUtils.isNotNull(info))