<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
spring-boot-starter-security
是Spring Security基础依赖,spring-security-oauth2-autoconfigure
是OAuth2自动配置模块
配置OAuth2认证服务器。在Spring Boot中,可以通过创建一个@Configuration
类并使用@EnableAuthorizationServer
注解来实现。
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.secret("{noop}secret") // 设置客户端的密码
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write")
.accessTokenValiditySeconds(3600)// 设置访问令牌有效期为1800秒
.refreshTokenValiditySeconds(86400);// 设置刷新令牌有效期为86400秒
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
}
上面代码中:创建了一个名为OAuth2Config的配置类并启用了@EnableAuthorizationServer注解,这表示我们正在创建一个OAuth2认证服务器。
通过configure(ClientDetailsServiceConfigurer clients)方法来配置OAuth2客户端详情服务,这里使用了内存存储客户端信息。configure(AuthorizationServerEndpointsConfigurer endpoints)方法用于配置OAuth2认证服务器的终端点,这里将认证管理器设置为authenticationManager
配置资源服务器,以便我们的应用程序能够保护资源并要求访问令牌进行身份验证和授权。
可以通过创建一个@Configuration
类并标注@EnableResourceServer
注解来实现:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**").authenticated()
.and().csrf().disable();
}
}
创建了一个名为ResourceServerConfig的配置类并启用了@EnableResourceServer注解,这表示我们正在创建一个OAuth2资源服务器。
此外,我们通过configure(HttpSecurity http)方法来配置HTTP安全性,这里我们要求任何访问/api/**的请求都必须经过身份验证才能访问。
需要配置安全,以便我们的应用程序可以使用安全协议来保护和管理OAuth2令牌。
可以通过创建一个@Configuration类并标注@EnableWebSecurity注解来实现:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.anyRequest().authenticated()
.and().csrf().disable();
}
}
创建了一个名为SecurityConfig的配置类并启用了@EnableWebSecurity注解,这表示我们正在创建一个Spring Security安全配置。
此外,我们通过configure(AuthenticationManagerBuilder auth)方法来配置用户详细信息服务和密码编码器。configure(HttpSecurity http)方法用于配置HTTP安全性,这里我们允许任何人访问/oauth/token端点,但对所有其他请求都要求进行身份验证。
# 获取访问令牌
curl -X POST \
http://localhost:8080/oauth/token \
-H 'Authorization: Basic Y2xpZW50OnNlY3JldA==' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=password&username=user&password=password'
# 使用访问令牌访问受保护的资源
curl -X GET \
http://localhost:8080/api/protected \
-H 'Authorization: Bearer <access_token>'
上面的命令中的Authorization头部的内容是base64编码的client:secret。在实际使用中,你需要替换成你自己的客户端ID和秘钥。
这是一个简单的使用Spring Boot和OAuth2实现认证和授权的示例。
package com.youming.shuiku.oauth2.config;
import com.youming.shuiku.oauth2.authentication.ding.DingTokenGranter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
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.ClientDetailsService;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* <p>
* Description:
* </p>
*
* @author wangxihao
* @version v1.0.0
* @ClassName AuthorizationServerConfiguration
* @Date 2022/10/20 15:15
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private BCryptPasswordEncoder passwordEncoder;
/**
* 注入用于支持 password 模式
*/
@Autowired
private AuthenticationManager authenticationManager;
// // 第一处修改,注入 RedisConnectionFactory,用于连接 Redis
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Lazy
@Resource(name = "userDetailsService")
private UserDetailsService userDetailsService;
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
// 配置数据源(注意,我使用的是 HikariCP 连接池),以上注解是指定数据源,否则会有冲突
return DataSourceBuilder.create().build();
}
@Bean
public TokenStore tokenStore() {
// 基于 JDBC 实现,令牌保存到数据库
// return new JdbcTokenStore(dataSource());
return new RedisTokenStore(redisConnectionFactory);
}
// @Bean
// @Primary
// public TokenStore jdbcTokenStore(){
// return new JdbcTokenStore(dataSource());
// }
@Bean
public ClientDetailsService jdbcClientDetailsService() {
// 基于 JDBC 实现,需要事先在数据库配置客户端信息
return new JdbcClientDetailsService(dataSource());
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 用于支持密码模式
// endpoints.authenticationManager(authenticationManager)
// // 增加 TokenStore 配置
// .tokenStore(tokenStore());
// endpoints.userDetailsService(userDetailsService);
// 获取原有默认授权模式(授权码模式、密码模式、客户端模式、简化模式)的授权者
List<TokenGranter> granterList = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
// 添加钉钉小程序授权模式的授权者
granterList.add(new DingTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory(), authenticationManager));
CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(granterList);
endpoints.authenticationManager(authenticationManager).tokenGranter(compositeTokenGranter)
.userDetailsService(userDetailsService).tokenStore(tokenStore());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
// 允许客户端访问 /oauth/check_token 检查 token
// .checkTokenAccess("isAuthenticated()");
// .tokenKeyAccess("permitAll()")z
.checkTokenAccess("permitAll()");
}
/**
* 配置客户端
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 客户端配置
clients.withClientDetails(jdbcClientDetailsService());
/*
* clients // 使用内存设置 .inMemory() // client_id .withClient("client") //
* client_secret .secret(passwordEncoder.encode("secret")) // 授权类型,密码模式和刷新令牌
* .authorizedGrantTypes("password", "refresh_token") // 授权范围 .scopes("backend")
* // 可以设置对哪些资源有访问权限,不设置则全部资源都可以访问 .resourceIds("backend-resources") //
* 设置访问令牌的有效期,这里是 1 天 .accessTokenValiditySeconds(60 * 60 * 24) // 设置刷新令牌的有效期,这里是
* 30 天 .refreshTokenValiditySeconds(60 * 60 * 24 * 30);
*/
}
}
package com.youming.shuiku.oauth2.config;
import com.youming.shuiku.oauth2.authentication.ding.DingAuthenticationProvider;
import com.youming.shuiku.oauth2.config.service.UserDetailsServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
/**
* 认证服务器安全配置
* <p>
* Description:
* </p>
*
* @author wangxihao
* @version v1.0.0
* @ClassName WebSecurityConfiguration
* @Date 2022/10/20 15:11
*/
@Configuration
@EnableWebSecurity
// 增加了资源服务器配置
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public BCryptPasswordEncoder passwordEncoder() {
// 配置默认的加密方式
return new BCryptPasswordEncoder();
}
@Bean
@Override
protected UserDetailsServiceImpl userDetailsService() {
return new UserDetailsServiceImpl();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 使用自定义认证与授权
// auth.userDetailsService(userDetailsService());
auth.authenticationProvider(daoAuthenticationProvider()).authenticationProvider(dingAuthenticationProvider());
}
/**
* 用于支持 password 模式
* @return
* @throws Exception
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/user/login")
.antMatchers("/user/refresh")
.antMatchers("/user/logins")
// .antMatchers("/info")
.antMatchers("/logout").antMatchers("/wx/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/login/**").permitAll()
// .and()
// .authorizeRequests()
// 增加了授权访问配置
// .antMatchers("/user/info").hasAuthority("USER")
// .antMatchers("/user/logout").hasAuthority("USER")
;
}
/**
* 钉钉小程序认证授权提供者
* @return
*/
@Bean
public DingAuthenticationProvider dingAuthenticationProvider() {
DingAuthenticationProvider provider = new DingAuthenticationProvider();
provider.setUserDetailsService(userDetailsService());
// provider.setWxMaService(wxMaService);
// provider.setMemberFeignClient(memberFeignClient);
return provider;
}
/**
* 用户名密码认证授权提供者
* @return
*/
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService());
provider.setPasswordEncoder(passwordEncoder());
provider.setHideUserNotFoundExceptions(false); // 是否隐藏用户不存在异常,默认:true-隐藏;false-抛出异常;
return provider;
}
}
对于用户验证,你可以实现UserDetailsService接口来定义从数据库或其他数据源中获取用户信息的逻辑
package com.youming.shuiku.oauth2.config.service;
import com.youming.shuiku.commons.constant.BaseConstant;
import com.youming.shuiku.commons.domain.SysUser;
import com.youming.shuiku.commons.response.ResponseCode;
import com.youming.shuiku.oauth2.service.ISysUserService;
import com.youming.shuiku.oauth2.userdetails.SysUserDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
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;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private ISysUserService sysUserService;
// @Autowired
// private IWechatUserRelService wechatUserRelService;
// @Autowired
// private ITbPermissionService tbPermissionService;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
// SysUser sysUser = sysUserService.getByUsername(s);
// List<GrantedAuthority> grantedAuthorities = Lists.newArrayList();
// grantedAuthorities.add(new SimpleGrantedAuthority("USER"));
//
// // 用户存在
// if (sysUser != null) {
// return new User(sysUser.getLoginAcct(), sysUser.getPassword(),
// grantedAuthorities);
// }
//
// // 用户不存在
// else {
// return null;
// }
SysUserDetails userDetails = null;
SysUser sysUser = sysUserService.getByMobile(s);
if (sysUser != null) {
if (sysUser.getUserType() == BaseConstant.UserType.THREE) {
userDetails = new SysUserDetails(sysUser, "THREE");
}
else {
userDetails = new SysUserDetails(sysUser, "USER");
}
}
if (userDetails == null) {
throw new UsernameNotFoundException(ResponseCode.USER_NOT_EXIST.message());
}
else if (!userDetails.isEnabled()) {
throw new DisabledException("该账户已被禁用!");
}
else if (!userDetails.isAccountNonLocked()) {
throw new LockedException("该账号已被锁定!");
}
else if (!userDetails.isAccountNonExpired()) {
throw new AccountExpiredException("该账号已过期!");
}
return userDetails;
}
/**
* userId 认证方式
* @param userId
* @return
*/
public UserDetails loadUserByUserId(String userId) {
SysUserDetails userDetails = null;
SysUser sysUser = sysUserService.getByUserId(userId);
if (sysUser != null) {
userDetails = new SysUserDetails(sysUser, "USER");
}
if (userDetails == null) {
throw new UsernameNotFoundException(ResponseCode.USER_NOT_EXIST.message());
}
else if (!userDetails.isEnabled()) {
// throw new DisabledException("该账户已被禁用!");
throw new DisabledException("用户已离职!");
}
else if (!userDetails.isAccountNonLocked()) {
throw new LockedException("该账号已被锁定!");
}
else if (!userDetails.isAccountNonExpired()) {
throw new AccountExpiredException("该账号已过期!");
}
return userDetails;
}
}
package com.youming.shuiku.oauth2.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.youming.shuiku.commons.base.web.Header;
import com.youming.shuiku.commons.domain.LoginInfo;
import com.youming.shuiku.commons.domain.SysUser;
import com.youming.shuiku.commons.exception.BusinessException;
import com.youming.shuiku.commons.response.ResponseCode;
import com.youming.shuiku.commons.response.ResponseResult;
import com.youming.shuiku.commons.util.RedisUtil;
import com.youming.shuiku.oauth2.Vo.LoginParam;
import com.youming.shuiku.oauth2.Vo.RefreshParam;
import com.youming.shuiku.oauth2.constant.OAuth2Constant;
import com.youming.shuiku.oauth2.dto.TokenDto;
import com.youming.shuiku.oauth2.service.ISysUserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* 前端控制器
* </p>
*
* @author wangxihao
* @since 2022-11-10
*/
@RestController
@RequestMapping("/user")
public class LoginController {
@Value("${security.oauth2.client.access-token-uri}")
public String accessTokenUri;
@Value("${security.oauth2.resource.token-info-uri}")
public String tokenInfoUri;
@Value("${security.oauth2.client.client-id}")
public String clientId;
@Value("${security.oauth2.client.client-secret}")
public String clientSecret;
@Value("${security.oauth2.dingding.client-id}")
public String dingdingClientId;
@Value("${security.oauth2.dingding.client-secret}")
public String dingdingClientSecret;
@Resource
private HttpServletRequest request;
@Resource
ISysUserService sysUserService;
// @Resource
// private IUserDeptService userDeptServicel;
@Resource
RedisUtil redisUtil;
@Resource
public BCryptPasswordEncoder passwordEncoder;
/**
* 管理员登录
*
* @param loginParam {@code JSON} {@link LoginParam}
* @return {@link ResponseResult}
*/
@PostMapping("login")
public ResponseResult admin(@RequestBody LoginParam loginParam) {
Integer platformType = loginParam.getPlatformType();
if (platformType == OAuth2Constant.LoginType.DINGDIND_APPLET) {
return dingdingLogin(loginParam);
} else if (platformType == OAuth2Constant.LoginType.WEB) {
return pcLogin(loginParam);
} else if (platformType == OAuth2Constant.LoginType.THREE) {
return threeLogin(loginParam);
} else {
return ResponseResult.failure();
}
}
/**
* 三方登录
* 提供三方系统以客户端模式登录
*
* @param loginParam {@code JSON} {@link LoginParam}
* @return {@link ResponseResult}
*/
public ResponseResult threeLogin(LoginParam loginParam) {
if (StringUtils.isEmpty(loginParam.getAppId()) || StringUtils.isEmpty(loginParam.getSecret())) {
throw new BusinessException(ResponseCode.PARAM_NOT_COMPLETE);
}
Map<String, Object> authParam = new HashMap<>();
// 三方登录客户端和密码接口回传
authParam.put("client_id", loginParam.getAppId());
authParam.put("client_secret", loginParam.getSecret());
authParam.put("grant_type", "client_credentials");
String strJson = HttpUtil.post(accessTokenUri, authParam);
JSONObject jsonObject = JSONUtil.parseObj(strJson);
String token = String.valueOf(jsonObject.get("access_token"));
if ("null".equals(token)) {
return ResponseResult.failure(String.valueOf(jsonObject.get("error_description")));
}
return ResponseResult.success(TokenDto.of(token, null));
}
/**
* 钉钉小程序登录
*
* @param loginParam
* @return
* @throws
* @author terry
* @date 2022/4/13 20:31
*/
private ResponseResult dingdingLogin(LoginParam loginParam) {
SysUser sysUser = sysUserService.getByUserId(loginParam.getUserId());
// 通过 HTTP 客户端请求登录接口
Map<String, Object> authParam = getAuthParam(2);
authParam.put("userId", sysUser.getUserId());
authParam.put("grant_type", "dingding");
return loginAccessToken(sysUser, authParam);
}
/**
* pc端登录--
*
* @param loginParam
* @return
* @throws
* @author terry
* @date 2022/4/13 20:30
*/
private ResponseResult pcLogin(LoginParam loginParam) {
SysUser sysUser = sysUserService.getByMobile(loginParam.getUsername());
if (sysUser == null) {
throw new BusinessException(ResponseCode.USER_LOGIN_ERROR);
}
if (sysUser.getState() != 1) {
throw new BusinessException(ResponseCode.User_DISABLED);
}
if(sysUser.getIsDel() == 1){
throw new BusinessException(ResponseCode.USER_DELETE);
}
// 验证密码是否正确
if (!passwordEncoder.matches(loginParam.getPassword(), sysUser.getPassword())) {
throw new BusinessException(ResponseCode.USER_LOGIN_ERROR);
}
// 通过 HTTP 客户端请求登录接口
Map<String, Object> authParam = getAuthParam(1);
// 三方登录客户端和密码接口回传
if (loginParam.getPlatformType() == OAuth2Constant.LoginType.THREE) {
authParam.put("client_id", loginParam.getAppId());
authParam.put("client_secret", loginParam.getSecret());
}
authParam.put("username", loginParam.getUsername());
authParam.put("password", loginParam.getPassword());
authParam.put("grant_type", "password");
// 获取accessToken
return loginAccessToken(sysUser, authParam);
}
/**
* 登录系统获取token
*
* @param sysUser
* @param authParam
* @return
* @throws
* @author terry
* @date 2022/4/13 21:25
*/
private ResponseResult loginAccessToken(SysUser sysUser, Map<String, Object> authParam) {
String strJson = HttpUtil.post(accessTokenUri, authParam);
JSONObject jsonObject = JSONUtil.parseObj(strJson);
String token = String.valueOf(jsonObject.get("access_token"));
String refresh = String.valueOf(jsonObject.get("refresh_token"));
if ("null".equals(token)) {
return ResponseResult.failure(String.valueOf(jsonObject.get("error_description")));
}
sysUser.setPassword("");
// redisUtil.setex("user:" + token, sysUser, 86400);
LoginInfo loginInfo = new LoginInfo();
BeanUtil.copyProperties(sysUser, loginInfo);
redisUtil.setex("loginInfo:" + token, loginInfo, 86400);
return ResponseResult.success(TokenDto.of(token, refresh));
}
/**
* 刷新令牌
*
* @return {@link ResponseResult}
*/
@PostMapping("refresh")
public ResponseResult refresh(@RequestBody RefreshParam refreshParam) {
String accessToken = Header.getAuthorization(request.getHeader("Authorization"));
Map<String, Object> authParam = getAuthParam(1);
authParam.put("grant_type", "refresh_token");
authParam.put("refresh_token",refreshParam.getRefresh());
String strJson = HttpUtil.post(accessTokenUri, authParam);
JSONObject jsonObject = JSONUtil.parseObj(strJson);
String token = String.valueOf(jsonObject.get("access_token"));
String refresh = String.valueOf(jsonObject.get("refresh_token"));
if ("null".equals(token)) {
return ResponseResult.failure(String.valueOf(jsonObject.get("error_description")));
}
// SysUser sysUser = (SysUser) redisUtil.get("user:" + accessToken);
redisUtil.del("user:" + accessToken);
// redisUtil.setex("user:" + token, sysUser, 86400);
LoginInfo loginInfo = (LoginInfo) redisUtil.get("loginInfo:" + accessToken);
redisUtil.del("loginInfo:" + accessToken);
redisUtil.setex("loginInfo:" + token, loginInfo, 86400);
return ResponseResult.success(TokenDto.of(token, refresh));
/*
* // AccessToken不存在直接返回null String refreshToken =
* refreshTokenMap.get(accessToken); if (StrUtil.isBlank(refreshToken)) { throw
* new BusinessException(ResponseCode.USER_NOT_LOGGED_IN); } // 通过HTTP 客户端请求刷新接口
* // 通过http 客户端请求登录接口 Map<String, Object> authParam = getAuthParam();
* authParam.put("grant_type", "refresh_token"); authParam.put("refresh_token",
* refreshToken);
*
* // 获取accessToken String strJson = HttpUtil.post(accessTokenUri, authParam);
* JSONObject jsonObject = JSONUtil.parseObj(strJson); String token =
* String.valueOf(jsonObject.get("access_token")); String refresh =
* String.valueOf(jsonObject.get("refresh_token")); if (StrUtil.isNotBlank(token)
* && StrUtil.isNotBlank(refresh)) { // 删除旧Token
* refreshTokenMap.remove(accessToken); // 将refresh_Token保存到服务端
* refreshTokenMap.put(token, refresh); result.put("token", token);
* ResponseResult.success(token); }
*/
}
/**
* 刷新令牌
*
* @return {@link ResponseResult}
*/
/*
* @GetMapping("info")
*
* @MyLog(value = "获取用户信息") // 这里添加了AOP的自定义注解 public ResponseResult info() { //
* 获取accessToken String userName =
* SecurityContextHolder.getContext().getAuthentication().getName();
*
* SysUser sysUser = sysUserService.getByUsername(userName); UserInfoDto dto = new
* UserInfoDto(); BeanUtils.copyProperties(sysUser, dto); return
* ResponseResult.success(dto); }
*/
// 私有方法-----------------------------------
private Map<String, Object> getAuthParam(int type) {
Map<String, Object> authParam = new HashMap<>();
if (type == 1) {
authParam.put("client_id", clientId);
authParam.put("client_secret", clientSecret);
} else if (type == 2) {
authParam.put("client_id", dingdingClientId);
authParam.put("client_secret", dingdingClientSecret);
}
return authParam;
}
@Resource
public TokenStore tokenStore;
@PostMapping("logout")
private ResponseResult logout(@RequestParam(value = "exit", defaultValue = "false") Boolean isExit) {
String token = Header.getAuthorization(request.getHeader("Authorization"));
// 删除token以注销
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
if (null != oAuth2AccessToken) {
if (isExit) {
tokenStore.removeAccessToken(oAuth2AccessToken);
}
return ResponseResult.success();
}
return ResponseResult.failure(ResponseCode.INTERFACE_ADDRESS_INVALID);
}
}
base:
config:
oauth:
hostname: 192.168.xx.xx
port: xxxx
nacos:
hostname: 192.168.xx.xx
port: xxxx
tidb:
hostname: 192.168.xx.xx
port: xxxx
redis:
hostname: 192.168.xx.xx
port: xxxx
password: xxxxxxxxxxx
# mongodb:
# hostname: 192.168.xx.xx
port: xxxx
spring:
application:
name: oauth2
main:
allow-bean-definition-overriding: true
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
cloud:
nacos:
discovery:
server-addr: ${base.config.nacos.hostname}:${base.config.nacos.port}
group: SHUIKU_GROUP
# namespace: 28ac7d69-8afd-474d-924d-28a291330188
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://${base.config.tidb.hostname}:${base.config.tidb.port}/shuiku_base?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: xxxxxxxxx
hikari:
minimum-idle: 5
idle-timeout: 600000
maximum-pool-size: 10
auto-commit: true
pool-name: MyHikariCP
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
redis:
# 你 Redis 主机地址
host: ${base.config.redis.hostname}
# 你 Redis 主机端口
port: ${base.config.redis.port}
# Redis服务器连接密码(默认为空)
password: ${base.config.redis.password}
# 我们使用 Lettuce 客户端,比 Jedis 更高效
lettuce:
# 连接池配置
pool:
# 连接池中的最小空闲连接,默认 0
min-idle: 0
# 连接池中的最大空闲连接,默认 8
max-idle: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制),默认 -1ms
max-wait: -1ms
# 连接池最大连接数(使用负值表示没有限制),默认 8
max-active: 8
server:
port: 9002
#logback
logging:
level:
com.youming.youche.oauth2: info
#将日志输出到文件
config: classpath:oauth2-log.xml
security:
oauth2:
client:
client-id: oauth
client-secret: oauth
access-token-uri: http://localhost:${server.port}/oauth/token
user-authorization-uri: http://localhost:${server.port}/oauth/authorize
resource:
token-info-uri: http://localhost:${server.port}/oauth/check_token
authorization:
check-token-access: http://localhost:${server.port}/oauth/check_token
dingding:
client-id: dingding
client-secret: dingding