mirror of
https://gitee.com/youlaitech/youlai-mall.git
synced 2024-12-23 13:03:43 +08:00
.
This commit is contained in:
parent
c93750d73c
commit
54747673ab
@ -1,14 +1,13 @@
|
|||||||
package com.youlai.mall.ums.pojo.dto;
|
package com.youlai.mall.ums.pojo.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
public class MemberAuthDTO {
|
public class MemberAuthDTO {
|
||||||
|
|
||||||
private Long id;
|
private Long userId;
|
||||||
private String username;
|
private String openId;
|
||||||
private Integer status;
|
private Integer status;
|
||||||
private String avatar;
|
|
||||||
private String nickname;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -65,13 +65,14 @@ public class MemberController {
|
|||||||
@ApiImplicitParam(name = "openid", value = "微信身份唯一标识", required = true, paramType = "path", dataType = "String")
|
@ApiImplicitParam(name = "openid", value = "微信身份唯一标识", required = true, paramType = "path", dataType = "String")
|
||||||
@GetMapping("/openid/{openid}")
|
@GetMapping("/openid/{openid}")
|
||||||
public Result<MemberAuthDTO> getByOpenid(@PathVariable String openid) {
|
public Result<MemberAuthDTO> getByOpenid(@PathVariable String openid) {
|
||||||
UmsMember member = iUmsMemberService.getOne(new LambdaQueryWrapper<UmsMember>().eq(UmsMember::getOpenid, openid));
|
UmsMember member = iUmsMemberService.getOne(new LambdaQueryWrapper<UmsMember>().eq(UmsMember::getOpenid, openid)
|
||||||
|
.select(UmsMember::getId,UmsMember::getOpenid,UmsMember::getStatus)
|
||||||
|
);
|
||||||
if (member == null) {
|
if (member == null) {
|
||||||
return Result.failed(ResultCode.USER_NOT_EXIST);
|
return Result.failed(ResultCode.USER_NOT_EXIST);
|
||||||
}
|
}
|
||||||
// 会员认证信息
|
// 会员认证信息
|
||||||
MemberAuthDTO memberAuth = new MemberAuthDTO();
|
MemberAuthDTO memberAuth = new MemberAuthDTO(member.getId(),member.getOpenid(),member.getStatus());
|
||||||
BeanUtil.copyProperties(member, memberAuth);
|
|
||||||
return Result.success(memberAuth);
|
return Result.success(memberAuth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserAuthDTO getByUsername(String username) {
|
public UserAuthDTO getByUsername(String username) {
|
||||||
return this.baseMapper.getByUsername(username);
|
UserAuthDTO userAuthInfo = this.baseMapper.getByUsername(username);
|
||||||
|
return userAuthInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,19 @@
|
|||||||
email,gmt_create,gmt_modified,
|
email,gmt_create,gmt_modified,
|
||||||
deleted
|
deleted
|
||||||
</sql>
|
</sql>
|
||||||
<select id="getByUsername" resultMap="BaseResultMap">
|
|
||||||
select t1.id, t1.username, t1.nickname, t1.password, t1.status, t3.code roleCode
|
<resultMap id="UserAuthMap" type="com.youlai.admin.pojo.dto.UserAuthDTO">
|
||||||
|
<id property="userId" column="id" jdbcType="BIGINT"/>
|
||||||
|
<result property="username" column="username" jdbcType="VARCHAR"/>
|
||||||
|
<result property="password" column="password" jdbcType="VARCHAR"/>
|
||||||
|
<result property="status" column="status" jdbcType="BOOLEAN"/>
|
||||||
|
<collection property="roles" ofType="string" javaType="list">
|
||||||
|
<result column="roleCode"></result>
|
||||||
|
</collection>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<select id="getByUsername" resultMap="UserAuthMap">
|
||||||
|
select t1.id userId, t1.username, t1.nickname, t1.password, t1.status, t3.code roleCode
|
||||||
from sys_user t1,
|
from sys_user t1,
|
||||||
sys_user_role t2,
|
sys_user_role t2,
|
||||||
sys_role t3
|
sys_role t3
|
||||||
|
@ -113,5 +113,4 @@
|
|||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -12,6 +12,8 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
|
|||||||
@EnableDiscoveryClient
|
@EnableDiscoveryClient
|
||||||
public class AuthApplication {
|
public class AuthApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
SpringApplication.run(AuthApplication.class, args);
|
SpringApplication.run(AuthApplication.class, args);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,6 @@ import cn.hutool.json.JSONUtil;
|
|||||||
import com.nimbusds.jose.jwk.JWKSet;
|
import com.nimbusds.jose.jwk.JWKSet;
|
||||||
import com.nimbusds.jose.jwk.RSAKey;
|
import com.nimbusds.jose.jwk.RSAKey;
|
||||||
import com.youlai.auth.common.enums.OAuthClientEnum;
|
import com.youlai.auth.common.enums.OAuthClientEnum;
|
||||||
import com.youlai.auth.domain.OAuthToken;
|
|
||||||
import com.youlai.auth.domain.UserInfo;
|
|
||||||
import com.youlai.auth.service.IAuthService;
|
|
||||||
import com.youlai.common.constant.AuthConstants;
|
import com.youlai.common.constant.AuthConstants;
|
||||||
import com.youlai.common.result.Result;
|
import com.youlai.common.result.Result;
|
||||||
import com.youlai.common.web.util.JwtUtils;
|
import com.youlai.common.web.util.JwtUtils;
|
||||||
@ -37,15 +34,14 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public class OAuthController {
|
public class OAuthController {
|
||||||
|
|
||||||
private TokenEndpoint tokenEndpoint;
|
private TokenEndpoint tokenEndpoint;
|
||||||
private IAuthService wechatAuthService;
|
|
||||||
private RedisTemplate redisTemplate;
|
private RedisTemplate redisTemplate;
|
||||||
private KeyPair keyPair;
|
private KeyPair keyPair;
|
||||||
|
|
||||||
@ApiOperation(value = "OAuth2认证", notes = "login")
|
@ApiOperation(value = "OAuth2认证", notes = "login")
|
||||||
@ApiImplicitParams({
|
@ApiImplicitParams({
|
||||||
@ApiImplicitParam(name = "grant_type", defaultValue = "password", value = "授权模式", required = true),
|
@ApiImplicitParam(name = "grant_type", defaultValue = "password", value = "授权模式", required = true),
|
||||||
@ApiImplicitParam(name = "client_id", value = "Oauth2客户端ID(新版本需放置请求头)", required = true),
|
@ApiImplicitParam(name = "client_id", value = "Oauth2客户端ID", required = true),
|
||||||
@ApiImplicitParam(name = "client_secret", value = "Oauth2客户端秘钥(新版本需放置请求头)", required = true),
|
@ApiImplicitParam(name = "client_secret", value = "Oauth2客户端秘钥", required = true),
|
||||||
@ApiImplicitParam(name = "refresh_token", value = "刷新token"),
|
@ApiImplicitParam(name = "refresh_token", value = "刷新token"),
|
||||||
@ApiImplicitParam(name = "username", defaultValue = "admin", value = "登录用户名"),
|
@ApiImplicitParam(name = "username", defaultValue = "admin", value = "登录用户名"),
|
||||||
@ApiImplicitParam(name = "password", defaultValue = "123456", value = "登录密码")
|
@ApiImplicitParam(name = "password", defaultValue = "123456", value = "登录密码")
|
||||||
@ -74,14 +70,6 @@ public class OAuthController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "微信授权登录")
|
|
||||||
@ApiImplicitParam(name = "code", value = "小程序授权code", paramType = "path")
|
|
||||||
@PostMapping("/wechat-token")
|
|
||||||
public Result wechatLogin(@PathVariable String code, @RequestBody UserInfo userInfo) {
|
|
||||||
OAuthToken token = wechatAuthService.login(code, userInfo);
|
|
||||||
return Result.success(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation(value = "注销", notes = "logout")
|
@ApiOperation(value = "注销", notes = "logout")
|
||||||
@DeleteMapping("/logout")
|
@DeleteMapping("/logout")
|
||||||
public Result logout() {
|
public Result logout() {
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package com.youlai.auth.domain;
|
|
||||||
|
|
||||||
import com.youlai.auth.common.jwt.JwtPayloadBuilder;
|
|
||||||
import lombok.*;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 描述: [自定义token]
|
|
||||||
* 创建时间: 2021/6/8
|
|
||||||
*
|
|
||||||
* @author hxr
|
|
||||||
* @version 1.0.0
|
|
||||||
* @update [序号][日期YYYY-MM-DD] [更改人姓名][变更描述]
|
|
||||||
*/
|
|
||||||
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Builder
|
|
||||||
@Data
|
|
||||||
public class OAuthToken {
|
|
||||||
|
|
||||||
private String access_token;
|
|
||||||
|
|
||||||
private String token_type = "bearer";
|
|
||||||
|
|
||||||
public OAuthToken accessToken(String accessToken) {
|
|
||||||
this.access_token = accessToken;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OAuthToken tokenType(String tokenType) {
|
|
||||||
this.token_type = tokenType;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -3,9 +3,9 @@ package com.youlai.auth.security.config;
|
|||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.http.HttpStatus;
|
import cn.hutool.http.HttpStatus;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.youlai.auth.security.core.userdetails.system.SysUserDetails;
|
|
||||||
import com.youlai.auth.security.core.clientdetails.ClientDetailsServiceImpl;
|
import com.youlai.auth.security.core.clientdetails.ClientDetailsServiceImpl;
|
||||||
import com.youlai.auth.security.core.userdetails.system.SysUserDetailsServiceImpl;
|
import com.youlai.auth.security.core.userdetails.system.SysUserDetails;
|
||||||
|
import com.youlai.auth.security.extension.wechat.WechatTokenGranter;
|
||||||
import com.youlai.common.result.Result;
|
import com.youlai.common.result.Result;
|
||||||
import com.youlai.common.result.ResultCode;
|
import com.youlai.common.result.ResultCode;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@ -16,14 +16,13 @@ import org.springframework.core.io.ClassPathResource;
|
|||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
|
||||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
|
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
|
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.AuthorizationServerConfigurerAdapter;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
|
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.AuthorizationServerEndpointsConfigurer;
|
||||||
|
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
|
||||||
|
import org.springframework.security.oauth2.provider.TokenGranter;
|
||||||
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
|
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
|
||||||
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
|
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
|
||||||
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
|
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
|
||||||
@ -42,7 +41,7 @@ import java.util.*;
|
|||||||
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
|
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
|
||||||
|
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
private SysUserDetailsServiceImpl sysUserDetailsService;
|
|
||||||
private ClientDetailsServiceImpl clientDetailsService;
|
private ClientDetailsServiceImpl clientDetailsService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,39 +58,29 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
|
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
|
||||||
|
// Token增强
|
||||||
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
|
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
|
||||||
List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
|
List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
|
||||||
tokenEnhancers.add(tokenEnhancer());
|
tokenEnhancers.add(tokenEnhancer());
|
||||||
tokenEnhancers.add(jwtAccessTokenConverter());
|
tokenEnhancers.add(jwtAccessTokenConverter());
|
||||||
tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
|
tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
|
||||||
|
|
||||||
|
// 添加自定义授权模式
|
||||||
|
List<TokenGranter> granterList = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
|
||||||
|
granterList.add(new WechatTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), authenticationManager));
|
||||||
|
CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(granterList);
|
||||||
|
|
||||||
endpoints
|
endpoints
|
||||||
.authenticationManager(authenticationManager)
|
.authenticationManager(authenticationManager)
|
||||||
.accessTokenConverter(jwtAccessTokenConverter())
|
.accessTokenConverter(jwtAccessTokenConverter())
|
||||||
.tokenEnhancer(tokenEnhancerChain)
|
.tokenEnhancer(tokenEnhancerChain)
|
||||||
// .userDetailsService(userDetailsService)
|
.tokenGranter(compositeTokenGranter)
|
||||||
// refresh token有两种使用方式:重复使用(true)、非重复使用(false),默认为true
|
// refresh token有两种使用方式:重复使用(true)、非重复使用(false),默认为true
|
||||||
// 1 重复使用:access token过期刷新时, refresh token过期时间未改变,仍以初次生成的时间为准
|
// 1 重复使用:access token过期刷新时, refresh token过期时间未改变,仍以初次生成的时间为准
|
||||||
// 2 非重复使用:access token过期刷新时, refresh token过期时间延续,在refresh token有效期内刷新便永不失效达到无需再次登录的目的
|
// 2 非重复使用:access token过期刷新时, refresh token过期时间延续,在refresh token有效期内刷新便永不失效达到无需再次登录的目的
|
||||||
.reuseRefreshTokens(true);
|
.reuseRefreshTokens(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重写 DaoAuthenticationProvider
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public DaoAuthenticationProvider authenticationProvider() {
|
|
||||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
|
||||||
provider.setHideUserNotFoundExceptions(false); // 是否隐藏用户不存在异常,默认:true-隐藏;false-抛出异常;
|
|
||||||
provider.setUserDetailsService(sysUserDetailsService);
|
|
||||||
provider.setPasswordEncoder(passwordEncoder());
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用非对称加密算法对token签名
|
* 使用非对称加密算法对token签名
|
||||||
*/
|
*/
|
||||||
@ -103,7 +92,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从classpath下的密钥库中获取密钥对(公钥+私钥)
|
* 密钥库中获取密钥对(公钥+私钥)
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public KeyPair keyPair() {
|
public KeyPair keyPair() {
|
||||||
@ -128,17 +117,6 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密码编码器
|
|
||||||
* <p>
|
|
||||||
* 委托方式,根据密码的前缀选择对应的encoder,例如:{bcypt}前缀->标识BCYPT算法加密;{noop}->标识不使用任何加密即明文的方式
|
|
||||||
* 密码判读 DaoAuthenticationProvider#additionalAuthenticationChecks
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public PasswordEncoder passwordEncoder() {
|
|
||||||
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义认证异常响应数据
|
* 自定义认证异常响应数据
|
||||||
*/
|
*/
|
||||||
|
@ -1,18 +1,31 @@
|
|||||||
package com.youlai.auth.security.config;
|
package com.youlai.auth.security.config;
|
||||||
|
|
||||||
|
import com.youlai.auth.security.core.userdetails.member.MemberUserDetailsServiceImpl;
|
||||||
|
import com.youlai.auth.security.core.userdetails.system.SysUserDetailsServiceImpl;
|
||||||
|
import com.youlai.auth.security.extension.wechat.WechatAuthenticationProvider;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
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.web.builders.HttpSecurity;
|
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.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
private final UserDetailsService sysUserDetailsService;
|
||||||
|
|
||||||
|
private final UserDetailsService memberUserDetailsService;
|
||||||
@Override
|
@Override
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
http
|
http
|
||||||
@ -25,7 +38,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证管理中心
|
* 认证管理对象
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
@ -35,5 +48,40 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
return super.authenticationManagerBean();
|
return super.authenticationManagerBean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(AuthenticationManagerBuilder auth) {
|
||||||
|
auth.authenticationProvider(wechatAuthenticationProvider())
|
||||||
|
.authenticationProvider(daoAuthenticationProvider());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WechatAuthenticationProvider wechatAuthenticationProvider() {
|
||||||
|
WechatAuthenticationProvider provider = new WechatAuthenticationProvider();
|
||||||
|
provider.setUserDetailsService(memberUserDetailsService);
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DaoAuthenticationProvider daoAuthenticationProvider() {
|
||||||
|
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||||
|
provider.setHideUserNotFoundExceptions(false); // 是否隐藏用户不存在异常,默认:true-隐藏;false-抛出异常;
|
||||||
|
provider.setUserDetailsService(sysUserDetailsService);
|
||||||
|
provider.setPasswordEncoder(passwordEncoder());
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码编码器
|
||||||
|
* <p>
|
||||||
|
* 委托方式,根据密码的前缀选择对应的encoder,例如:{bcypt}前缀->标识BCYPT算法加密;{noop}->标识不使用任何加密即明文的方式
|
||||||
|
* 密码判读 DaoAuthenticationProvider#additionalAuthenticationChecks
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public PasswordEncoder passwordEncoder() {
|
||||||
|
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import java.util.Collection;
|
|||||||
public class MemberUserDetails implements UserDetails {
|
public class MemberUserDetails implements UserDetails {
|
||||||
|
|
||||||
private Long userId;
|
private Long userId;
|
||||||
|
private String openId;
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
private Collection<SimpleGrantedAuthority> authorities;
|
private Collection<SimpleGrantedAuthority> authorities;
|
||||||
|
|
||||||
@ -31,11 +32,11 @@ public class MemberUserDetails implements UserDetails {
|
|||||||
* @param member 小程序会员用户认证信息
|
* @param member 小程序会员用户认证信息
|
||||||
*/
|
*/
|
||||||
public MemberUserDetails(MemberAuthDTO member) {
|
public MemberUserDetails(MemberAuthDTO member) {
|
||||||
this.setUserId(member.getId());
|
this.setUserId(member.getUserId());
|
||||||
|
this.setOpenId(member.getOpenId());
|
||||||
this.setEnabled(GlobalConstants.STATUS_YES.equals(member.getStatus()));
|
this.setEnabled(GlobalConstants.STATUS_YES.equals(member.getStatus()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
return this.authorities;
|
return this.authorities;
|
||||||
@ -48,7 +49,7 @@ public class MemberUserDetails implements UserDetails {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
return null;
|
return this.openId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package com.youlai.auth.security.core.userdetails.member;
|
package com.youlai.auth.security.core.userdetails.member;
|
||||||
|
|
||||||
|
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||||
|
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||||
import com.youlai.common.result.Result;
|
import com.youlai.common.result.Result;
|
||||||
import com.youlai.common.result.ResultCode;
|
import com.youlai.common.result.ResultCode;
|
||||||
import com.youlai.mall.ums.api.MemberFeignClient;
|
import com.youlai.mall.ums.api.MemberFeignClient;
|
||||||
import com.youlai.mall.ums.pojo.dto.MemberAuthDTO;
|
import com.youlai.mall.ums.pojo.dto.MemberAuthDTO;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.authentication.AccountExpiredException;
|
import org.springframework.security.authentication.AccountExpiredException;
|
||||||
import org.springframework.security.authentication.DisabledException;
|
import org.springframework.security.authentication.DisabledException;
|
||||||
@ -19,21 +22,33 @@ import org.springframework.stereotype.Service;
|
|||||||
*
|
*
|
||||||
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
|
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service("memberUserDetailsService")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class MemberUserDetailsServiceImpl implements UserDetailsService {
|
public class MemberUserDetailsServiceImpl implements UserDetailsService {
|
||||||
|
|
||||||
private final MemberFeignClient memberFeignClient;
|
private final MemberFeignClient memberFeignClient;
|
||||||
|
|
||||||
|
private final WxMaService wxMaService;
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
@Override
|
@Override
|
||||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
public UserDetails loadUserByUsername(String code) throws UsernameNotFoundException {
|
||||||
MemberUserDetails userDetails = null;
|
MemberUserDetails userDetails = null;
|
||||||
Result<MemberAuthDTO> result = memberFeignClient.loadUserByOpenId(username);
|
WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
|
||||||
|
String openid = sessionInfo.getOpenid();
|
||||||
|
|
||||||
|
|
||||||
|
Result<MemberAuthDTO> result = memberFeignClient.loadUserByOpenId(openid);
|
||||||
if (Result.isSuccess(result)) {
|
if (Result.isSuccess(result)) {
|
||||||
MemberAuthDTO member = result.getData();
|
MemberAuthDTO member = result.getData();
|
||||||
if (null != member) {
|
if (null != member) {
|
||||||
userDetails = new MemberUserDetails(member);
|
userDetails = new MemberUserDetails(member);
|
||||||
|
} else { // 微信用户不存在同步微信用户信息注册为小程序会员
|
||||||
|
|
||||||
|
//wxMaService.getUserService().getUserInfo()
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (userDetails == null) {
|
if (userDetails == null) {
|
||||||
|
@ -52,18 +52,6 @@ public class SysUserDetails implements UserDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 小程序会员用户体系
|
|
||||||
*
|
|
||||||
* @param member 小程序会员用户认证信息
|
|
||||||
*/
|
|
||||||
public SysUserDetails(MemberAuthDTO member) {
|
|
||||||
this.setUserId(member.getId());
|
|
||||||
this.setUsername(member.getUsername());
|
|
||||||
this.setEnabled(GlobalConstants.STATUS_YES.equals(member.getStatus()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
return this.authorities;
|
return this.authorities;
|
||||||
|
@ -19,7 +19,7 @@ import org.springframework.stereotype.Service;
|
|||||||
*
|
*
|
||||||
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
|
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service("sysUserDetailsService")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class SysUserDetailsServiceImpl implements UserDetailsService {
|
public class SysUserDetailsServiceImpl implements UserDetailsService {
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
package com.youlai.auth.domain;
|
package com.youlai.auth.security.extension.wechat;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 描述: [微信用户信息]
|
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
|
||||||
* 创建时间: 2021/6/8
|
* @date 2021/9/29
|
||||||
*
|
|
||||||
* @author hxr
|
|
||||||
*/
|
*/
|
||||||
@Data
|
|
||||||
public class UserInfo {
|
public class UserInfo {
|
||||||
|
|
||||||
private String avatarUrl;
|
private String avatarUrl;
|
@ -1,20 +1,25 @@
|
|||||||
package com.youlai.auth.security.extension.wechat;
|
package com.youlai.auth.security.extension.wechat;
|
||||||
|
|
||||||
import com.youlai.auth.security.core.userdetails.member.MemberUserDetailsServiceImpl;
|
import lombok.Data;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
|
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
|
||||||
* @date 2021/9/25
|
* @date 2021/9/25
|
||||||
*/
|
*/
|
||||||
|
@Data
|
||||||
public class WechatAuthenticationProvider implements AuthenticationProvider {
|
public class WechatAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
|
||||||
private MemberUserDetailsServiceImpl memberUserDetailsService;
|
private UserDetailsService userDetailsService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 用户认证
|
||||||
|
*
|
||||||
* @param authentication
|
* @param authentication
|
||||||
* @return
|
* @return
|
||||||
* @throws AuthenticationException
|
* @throws AuthenticationException
|
||||||
@ -22,10 +27,10 @@ public class WechatAuthenticationProvider implements AuthenticationProvider {
|
|||||||
@Override
|
@Override
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
WechatAuthenticationToken authenticationToken = (WechatAuthenticationToken) authentication;
|
WechatAuthenticationToken authenticationToken = (WechatAuthenticationToken) authentication;
|
||||||
String openId = (String) authenticationToken.getPrincipal();
|
String code = (String) authenticationToken.getPrincipal();
|
||||||
UserDetails userDetails = memberUserDetailsService.loadUserByUsername(openId);
|
UserDetails userDetails = userDetailsService.loadUserByUsername(code);
|
||||||
|
|
||||||
WechatAuthenticationToken result = new WechatAuthenticationToken(openId, userDetails.getAuthorities());
|
WechatAuthenticationToken result = new WechatAuthenticationToken(userDetails.getUsername(), userDetails.getAuthorities());
|
||||||
result.setDetails(authentication.getDetails());
|
result.setDetails(authentication.getDetails());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,23 @@ public class WechatAuthenticationToken extends AbstractAuthenticationToken {
|
|||||||
|
|
||||||
private final Object principal;
|
private final Object principal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 账号校验之前的token构建
|
||||||
|
*
|
||||||
|
* @param principal
|
||||||
|
*/
|
||||||
public WechatAuthenticationToken(Object principal) {
|
public WechatAuthenticationToken(Object principal) {
|
||||||
super(null);
|
super(null);
|
||||||
this.principal = principal;
|
this.principal = principal;
|
||||||
setAuthenticated(false);
|
setAuthenticated(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 账号校验成功之后的token构建
|
||||||
|
*
|
||||||
|
* @param principal
|
||||||
|
* @param authorities
|
||||||
|
*/
|
||||||
public WechatAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
|
public WechatAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
|
||||||
super(authorities);
|
super(authorities);
|
||||||
this.principal = principal;
|
this.principal = principal;
|
||||||
@ -37,7 +48,6 @@ public class WechatAuthenticationToken extends AbstractAuthenticationToken {
|
|||||||
return this.principal;
|
return this.principal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
|
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
|
||||||
Assert.isTrue(!isAuthenticated, "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
|
Assert.isTrue(!isAuthenticated, "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
|
||||||
|
@ -19,8 +19,8 @@ public class WechatTokenGranter extends AbstractTokenGranter {
|
|||||||
private static final String GRANT_TYPE = "wechat";
|
private static final String GRANT_TYPE = "wechat";
|
||||||
private final AuthenticationManager authenticationManager;
|
private final AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
protected WechatTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType, AuthenticationManager authenticationManager) {
|
public WechatTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, AuthenticationManager authenticationManager) {
|
||||||
super(tokenServices, clientDetailsService, requestFactory, grantType);
|
super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
|
||||||
this.authenticationManager = authenticationManager;
|
this.authenticationManager = authenticationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,21 +28,27 @@ public class WechatTokenGranter extends AbstractTokenGranter {
|
|||||||
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
|
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
|
||||||
|
|
||||||
Map<String, String> parameters = new LinkedHashMap(tokenRequest.getRequestParameters());
|
Map<String, String> parameters = new LinkedHashMap(tokenRequest.getRequestParameters());
|
||||||
String openId = parameters.get("openId");
|
String code = parameters.get("code");
|
||||||
Authentication userAuth = new WechatAuthenticationToken(openId);
|
String rawData = parameters.get("rawData");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
parameters.remove("code");
|
||||||
|
parameters.remove("rawData");
|
||||||
|
Authentication userAuth = new WechatAuthenticationToken(code); // 未认证状态
|
||||||
((AbstractAuthenticationToken) userAuth).setDetails(parameters);
|
((AbstractAuthenticationToken) userAuth).setDetails(parameters);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
userAuth = this.authenticationManager.authenticate(userAuth); // 参数校验
|
userAuth = this.authenticationManager.authenticate(userAuth); // 认证中
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new InvalidGrantException(e.getMessage());
|
throw new InvalidGrantException(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userAuth != null && userAuth.isAuthenticated()) {
|
if (userAuth != null && userAuth.isAuthenticated()) { // 认证成功
|
||||||
OAuth2Request storedOAuth2Request = this.getRequestFactory().createOAuth2Request(client, tokenRequest);
|
OAuth2Request storedOAuth2Request = this.getRequestFactory().createOAuth2Request(client, tokenRequest);
|
||||||
return new OAuth2Authentication(storedOAuth2Request, userAuth);
|
return new OAuth2Authentication(storedOAuth2Request, userAuth);
|
||||||
} else {
|
} else { // 认证失败
|
||||||
throw new InvalidGrantException("Could not authenticate user: " + openId);
|
throw new InvalidGrantException("Could not authenticate code: " + code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
package com.youlai.auth.service;
|
|
||||||
|
|
||||||
import com.youlai.auth.domain.OAuthToken;
|
|
||||||
import com.youlai.auth.domain.UserInfo;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 描述: [类型描述]
|
|
||||||
* 创建时间: 2021/6/8
|
|
||||||
*
|
|
||||||
* @author hxr
|
|
||||||
* @version 1.0.0
|
|
||||||
* @update [序号][日期YYYY-MM-DD] [更改人姓名][变更描述]
|
|
||||||
*/
|
|
||||||
public interface IAuthService {
|
|
||||||
|
|
||||||
OAuthToken login(String code, UserInfo userInfo);
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
package com.youlai.auth.service.impl;
|
|
||||||
|
|
||||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
|
||||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
|
||||||
import cn.hutool.core.convert.Convert;
|
|
||||||
import cn.hutool.core.lang.Assert;
|
|
||||||
import com.youlai.auth.common.jwt.JwtGenerator;
|
|
||||||
import com.youlai.auth.domain.OAuthToken;
|
|
||||||
import com.youlai.auth.domain.UserInfo;
|
|
||||||
import com.youlai.auth.service.IAuthService;
|
|
||||||
import com.youlai.common.constant.AuthConstants;
|
|
||||||
import com.youlai.common.result.Result;
|
|
||||||
import com.youlai.common.result.ResultCode;
|
|
||||||
import com.youlai.mall.ums.api.MemberFeignClient;
|
|
||||||
import com.youlai.mall.ums.pojo.entity.UmsMember;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author haoxr
|
|
||||||
* @description 微信小程序认证接口
|
|
||||||
* @createTime 2021/5/20 23:37
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class WechatAuthServiceImpl implements IAuthService {
|
|
||||||
|
|
||||||
private MemberFeignClient memberFeignClient;
|
|
||||||
private WxMaService wxMaService;
|
|
||||||
private JwtGenerator jwtGenerator;
|
|
||||||
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Override
|
|
||||||
public OAuthToken login(String code, UserInfo userInfo) {
|
|
||||||
// 微信小程序的授权code获取openid
|
|
||||||
WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
|
|
||||||
String openid = sessionInfo.getOpenid();
|
|
||||||
Result<UmsMember> result = memberFeignClient.getByOpenid(openid);
|
|
||||||
UmsMember member;
|
|
||||||
if (ResultCode.USER_NOT_EXIST.getCode().equals(result.getCode())) {
|
|
||||||
// 用户不存在,注册成为新用户
|
|
||||||
member = new UmsMember();
|
|
||||||
BeanUtil.copyProperties(userInfo, member);
|
|
||||||
member.setOpenid(openid);
|
|
||||||
Result<Long> addRes = memberFeignClient.add(member);
|
|
||||||
Assert.isTrue(ResultCode.SUCCESS.getCode().equals(addRes.getCode()), "微信用户注册失败");
|
|
||||||
member.setId(addRes.getData()); // 新增后有了会员ID
|
|
||||||
} else {
|
|
||||||
member = result.getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自定义JWT生成
|
|
||||||
// 1. JWT授权,一般存放用户的角色标识,用于资源服务器(网关)鉴权
|
|
||||||
Set<String> authorities = new HashSet<>();
|
|
||||||
// 2. JWT增强,携带用户ID等信息
|
|
||||||
Map<String, String> additional = new HashMap<>();
|
|
||||||
additional.put(AuthConstants.USER_ID_KEY, Convert.toStr(member.getId()));
|
|
||||||
String accessToken = jwtGenerator.createAccessToken(authorities, additional);
|
|
||||||
|
|
||||||
OAuthToken token = new OAuthToken().accessToken(accessToken);
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user