mirror of
https://gitee.com/incloudcode/yexuejc-springboot.git
synced 2025-07-13 23:37:28 +08:00
springboot security 登录集成(含账号登录、短信登录、第三方登录)
This commit is contained in:
parent
2ea6e8c536
commit
6eb91109ac
@ -92,6 +92,29 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- HikariCP数据库连接池(JDK1.8) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.zaxxer</groupId>
|
||||||
|
<artifactId>HikariCP</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- springboot mybatis-plus-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- 内存数据库h2-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -68,7 +68,7 @@ public class OssFacade {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private OSSClient ossClient() {
|
private OSSClient ossClient() {
|
||||||
return new OSSClient(properties.getEndpoint(), properties.getAccessKeyID(), properties.getAccessKeySecret(),
|
return new OSSClient(properties.getEndpoint(), properties.getAccessKeyId(), properties.getAccessKeySecret(),
|
||||||
configuration);
|
configuration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,4 +69,25 @@ public class BizConsts {
|
|||||||
*/
|
*/
|
||||||
public static String BASE_NOT_LOGIN_CODE = BASE_CODE + "010";
|
public static String BASE_NOT_LOGIN_CODE = BASE_CODE + "010";
|
||||||
public static String BASE_NOT_LOGIN_MSG = "您尚未登陆";
|
public static String BASE_NOT_LOGIN_MSG = "您尚未登陆";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户登录发送短信验证码
|
||||||
|
*/
|
||||||
|
public static String CONSUMER_LOGIN_SMS = "consumer.login.sendSms";
|
||||||
|
/**
|
||||||
|
* 用户绑定手机号
|
||||||
|
*/
|
||||||
|
public static String CONSUMER_BIND_MOBILE = "consumer.bind.mobile.sms";
|
||||||
|
/**
|
||||||
|
* 用户登录信息
|
||||||
|
*/
|
||||||
|
public static String CONSUMER_LOGIN_REDIS = "consumer.login.redis.session";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台管理员登录信息
|
||||||
|
*/
|
||||||
|
public static String ADMIN_LOGIN_REDIS = "admin.login.redis.session";
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.yexuejc.springboot.base.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册类型
|
||||||
|
* @author: maxf
|
||||||
|
* @date: 2018/8/6 21:43:58
|
||||||
|
*/
|
||||||
|
public class DictRegTypeConsts {
|
||||||
|
/**
|
||||||
|
* A : 账号注册
|
||||||
|
*/
|
||||||
|
public static final String DICT_ACCOUNT = "A";
|
||||||
|
/**
|
||||||
|
* B : 微博注册
|
||||||
|
*/
|
||||||
|
public static final String DICT_WEIBO = "B";
|
||||||
|
/**
|
||||||
|
* Q : qq注册
|
||||||
|
*/
|
||||||
|
public static final String DICT_QQ = "Q";
|
||||||
|
/**
|
||||||
|
* S : 手机号注册
|
||||||
|
*/
|
||||||
|
public static final String DICT_MOBILE = "S";
|
||||||
|
/**
|
||||||
|
* W : 微信注册
|
||||||
|
*/
|
||||||
|
public static final String DICT_WECHAT = "W";
|
||||||
|
|
||||||
|
private DictRegTypeConsts() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.yexuejc.springboot.base.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录方式
|
||||||
|
*
|
||||||
|
* @author: maxf
|
||||||
|
* @date: 2018/9/9 12:22:53
|
||||||
|
*/
|
||||||
|
public class LogTypeConsts {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短信登录
|
||||||
|
*/
|
||||||
|
public static final String SMS = "sms";
|
||||||
|
/**
|
||||||
|
* QQ 登录
|
||||||
|
*/
|
||||||
|
public static final String QQ = "qq";
|
||||||
|
/**
|
||||||
|
* 微信
|
||||||
|
*/
|
||||||
|
public static final String WECHAT = "wechat";
|
||||||
|
/**
|
||||||
|
* 微博
|
||||||
|
*/
|
||||||
|
public static final String WEIBO = "weibo";
|
||||||
|
/**
|
||||||
|
* 账号
|
||||||
|
*/
|
||||||
|
public static final String ACCOUNT = "account";
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.yexuejc.springboot.base.exception;
|
||||||
|
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方授权异常
|
||||||
|
*
|
||||||
|
* @author: maxf
|
||||||
|
* @date: 2018/5/27 19:20
|
||||||
|
*/
|
||||||
|
public class ThirdPartyAuthorizationException extends AuthenticationException {
|
||||||
|
/**
|
||||||
|
* 错误码
|
||||||
|
*/
|
||||||
|
private String code = "E";
|
||||||
|
|
||||||
|
public ThirdPartyAuthorizationException(String msg, Throwable t) {
|
||||||
|
super(msg, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThirdPartyAuthorizationException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThirdPartyAuthorizationException() {
|
||||||
|
super("授权异常");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThirdPartyAuthorizationException(Throwable t) {
|
||||||
|
super("授权异常", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ThirdPartyAuthorizationException(String code, String message) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
public ThirdPartyAuthorizationException(String code, String msg, Throwable t) {
|
||||||
|
super(msg, t);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,275 @@
|
|||||||
|
package com.yexuejc.springboot.base.security;
|
||||||
|
|
||||||
|
import com.yexuejc.springboot.base.constant.LogTypeConsts;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||||
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public class ConsumerAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
|
||||||
|
// ~ Static fields/initializers
|
||||||
|
// =====================================================================================
|
||||||
|
|
||||||
|
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
|
||||||
|
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
|
||||||
|
/**
|
||||||
|
* 登录方式
|
||||||
|
*/
|
||||||
|
public static final String SPRING_SECURITY_FORM_LOGTYPE_KEY = "logtype";
|
||||||
|
public static final String SPRING_SECURITY_FORM_OPENID_KEY = "openid";
|
||||||
|
/********************************** 第三方登录时附带信息*************************************/
|
||||||
|
/**
|
||||||
|
* 头像
|
||||||
|
*/
|
||||||
|
public static final String SPRING_SECURITY_FORM_HEAD_KEY = "head";
|
||||||
|
/**
|
||||||
|
* 昵称
|
||||||
|
*/
|
||||||
|
public static final String SPRING_SECURITY_FORM_NICKNAME_KEY = "nickname";
|
||||||
|
/**
|
||||||
|
* 性别
|
||||||
|
*/
|
||||||
|
public static final String SPRING_SECURITY_FORM_SEX_KEY = "sex";
|
||||||
|
/********************************** 第三方登录时附带信息*************************************/
|
||||||
|
|
||||||
|
private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
|
||||||
|
private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
|
||||||
|
private String logtypeParameter = SPRING_SECURITY_FORM_LOGTYPE_KEY;
|
||||||
|
private String openidParameter = SPRING_SECURITY_FORM_OPENID_KEY;
|
||||||
|
private String headParameter = SPRING_SECURITY_FORM_HEAD_KEY;
|
||||||
|
private String nicknameParameter = SPRING_SECURITY_FORM_NICKNAME_KEY;
|
||||||
|
private String sexParameter = SPRING_SECURITY_FORM_SEX_KEY;
|
||||||
|
private boolean postOnly = true;
|
||||||
|
private boolean reverse = true;
|
||||||
|
|
||||||
|
// ~ Constructors
|
||||||
|
// ===================================================================================================
|
||||||
|
|
||||||
|
protected ConsumerAuthenticationProcessingFilter(AuthenticationManager authenticationManager) {
|
||||||
|
super(new AntPathRequestMatcher("/login", "POST"));
|
||||||
|
setAuthenticationManager(authenticationManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ConsumerAuthenticationProcessingFilter() {
|
||||||
|
super(new AntPathRequestMatcher("/login", "POST"));
|
||||||
|
}
|
||||||
|
// ~ Methods
|
||||||
|
// ========================================================================================================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authentication attemptAuthentication(HttpServletRequest request,
|
||||||
|
HttpServletResponse response) throws AuthenticationException {
|
||||||
|
return displyAuthentication(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 可继承自定义处理登录请求
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @return
|
||||||
|
* @throws AuthenticationException
|
||||||
|
*/
|
||||||
|
protected Authentication displyAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||||
|
if (postOnly && !request.getMethod().equals("POST")) {
|
||||||
|
throw new AuthenticationServiceException(
|
||||||
|
"Authentication method not supported: " + request.getMethod());
|
||||||
|
}
|
||||||
|
String logtype = obtainLogtype(request);
|
||||||
|
System.out.println("登录方式:" + logtype);
|
||||||
|
String username = "";
|
||||||
|
String password = "";
|
||||||
|
if (logtype == null) {
|
||||||
|
logtype = "";
|
||||||
|
}
|
||||||
|
String openid = "";
|
||||||
|
String smscode = "";
|
||||||
|
/**第三方登录:微信 用户头像*/
|
||||||
|
String head = "";
|
||||||
|
String nickname = "";
|
||||||
|
String sex = "";
|
||||||
|
//根据不同登录方式做不同处理
|
||||||
|
getParams(request, logtype, username, password, smscode, openid, sex, head, nickname);
|
||||||
|
UsernamePasswordAuthenticationToken authRequest = new ConsumerToken(
|
||||||
|
logtype, smscode, openid, username, password, head, nickname, sex);
|
||||||
|
|
||||||
|
// Allow subclasses to set the "details" property
|
||||||
|
setDetails(request, authRequest);
|
||||||
|
//ProviderManager 这东西会先把DaoAuthenticationProvider加入列表,导致setHideUserNotFoundExceptions(false);被覆盖
|
||||||
|
if (this.getAuthenticationManager() instanceof ProviderManager && reverse) {
|
||||||
|
reverse = false;
|
||||||
|
ProviderManager providerManager = (ProviderManager) this.getAuthenticationManager();
|
||||||
|
providerManager.getProviders().forEach(it -> {
|
||||||
|
((AbstractUserDetailsAuthenticationProvider) it).setHideUserNotFoundExceptions(false);
|
||||||
|
});
|
||||||
|
Collections.reverse(providerManager.getProviders());
|
||||||
|
}
|
||||||
|
return this.getAuthenticationManager().authenticate(authRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据登录方式获取请求参数
|
||||||
|
*
|
||||||
|
* @param request 登录请求
|
||||||
|
* @param logtype 登录类型
|
||||||
|
* @param username 账号
|
||||||
|
* @param password 密码
|
||||||
|
* @param smscode 短信验证码
|
||||||
|
* @param openid 第三封授权id
|
||||||
|
* @param sex 附加:性别
|
||||||
|
* @param head 附加:头像(源头像路径)
|
||||||
|
* @param nickname 附加:昵称
|
||||||
|
*/
|
||||||
|
protected void getParams(HttpServletRequest request, String logtype, String username, String password,
|
||||||
|
String smscode, String openid, String sex, String head, String nickname) {
|
||||||
|
switch (logtype) {
|
||||||
|
case LogTypeConsts.SMS:
|
||||||
|
//短信登录
|
||||||
|
username = obtainUsername(request);
|
||||||
|
smscode = obtainPassword(request);
|
||||||
|
break;
|
||||||
|
case LogTypeConsts.QQ:
|
||||||
|
//QQ登录
|
||||||
|
openid = obtainOpenid(request);
|
||||||
|
head = obtainHead(request);
|
||||||
|
nickname = obtainNickname(request);
|
||||||
|
sex = obtainSex(request);
|
||||||
|
break;
|
||||||
|
case LogTypeConsts.WECHAT:
|
||||||
|
//微信登录
|
||||||
|
openid = obtainOpenid(request);
|
||||||
|
head = obtainHead(request);
|
||||||
|
nickname = obtainNickname(request);
|
||||||
|
sex = obtainSex(request);
|
||||||
|
break;
|
||||||
|
case LogTypeConsts.WEIBO:
|
||||||
|
//微博登录
|
||||||
|
openid = obtainOpenid(request);
|
||||||
|
head = obtainHead(request);
|
||||||
|
nickname = obtainNickname(request);
|
||||||
|
sex = obtainSex(request);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//默认账号+密码登录
|
||||||
|
username = obtainUsername(request).trim();
|
||||||
|
password = obtainPassword(request);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables subclasses to override the composition of the password, such as by
|
||||||
|
* including additional values and a separator.
|
||||||
|
* <p>
|
||||||
|
* This might be used for example if a postcode/zipcode was required in addition to
|
||||||
|
* the password. A delimiter such as a pipe (|) should be used to separate the
|
||||||
|
* password and extended value(s). The <code>AuthenticationDao</code> will need to
|
||||||
|
* generate the expected password in a corresponding manner.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param request so that request attributes can be retrieved
|
||||||
|
* @return the password that will be presented in the <code>Authentication</code>
|
||||||
|
* request token to the <code>AuthenticationManager</code>
|
||||||
|
*/
|
||||||
|
protected String obtainPassword(HttpServletRequest request) {
|
||||||
|
return request.getParameter(passwordParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables subclasses to override the composition of the username, such as by
|
||||||
|
* including additional values and a separator.
|
||||||
|
*
|
||||||
|
* @param request so that request attributes can be retrieved
|
||||||
|
* @return the username that will be presented in the <code>Authentication</code>
|
||||||
|
* request token to the <code>AuthenticationManager</code>
|
||||||
|
*/
|
||||||
|
protected String obtainUsername(HttpServletRequest request) {
|
||||||
|
return request.getParameter(usernameParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String obtainLogtype(HttpServletRequest request) {
|
||||||
|
return request.getParameter(logtypeParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String obtainOpenid(HttpServletRequest request) {
|
||||||
|
return request.getParameter(openidParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String obtainHead(HttpServletRequest request) {
|
||||||
|
return request.getParameter(headParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String obtainNickname(HttpServletRequest request) {
|
||||||
|
return request.getParameter(nicknameParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String obtainSex(HttpServletRequest request) {
|
||||||
|
return request.getParameter(sexParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provided so that subclasses may configure what is put into the authentication
|
||||||
|
* request's details property.
|
||||||
|
*
|
||||||
|
* @param request that an authentication request is being created for
|
||||||
|
* @param authRequest the authentication request object that should have its details
|
||||||
|
* set
|
||||||
|
*/
|
||||||
|
protected void setDetails(HttpServletRequest request,
|
||||||
|
UsernamePasswordAuthenticationToken authRequest) {
|
||||||
|
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the parameter name which will be used to obtain the username from the login
|
||||||
|
* request.
|
||||||
|
*
|
||||||
|
* @param usernameParameter the parameter name. Defaults to "username".
|
||||||
|
*/
|
||||||
|
public void setUsernameParameter(String usernameParameter) {
|
||||||
|
Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
|
||||||
|
this.usernameParameter = usernameParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the parameter name which will be used to obtain the password from the login
|
||||||
|
* request..
|
||||||
|
*
|
||||||
|
* @param passwordParameter the parameter name. Defaults to "password".
|
||||||
|
*/
|
||||||
|
public void setPasswordParameter(String passwordParameter) {
|
||||||
|
Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
|
||||||
|
this.passwordParameter = passwordParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines whether only HTTP POST requests will be allowed by this filter. If set to
|
||||||
|
* true, and an authentication request is received which is not a POST request, an
|
||||||
|
* exception will be raised immediately and authentication will not be attempted. The
|
||||||
|
* <tt>unsuccessfulAuthentication()</tt> method will be called as if handling a failed
|
||||||
|
* authentication.
|
||||||
|
* <p>
|
||||||
|
* Defaults to <tt>true</tt> but may be overridden by subclasses.
|
||||||
|
*/
|
||||||
|
public void setPostOnly(boolean postOnly) {
|
||||||
|
this.postOnly = postOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getUsernameParameter() {
|
||||||
|
return usernameParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getPasswordParameter() {
|
||||||
|
return passwordParameter;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,290 @@
|
|||||||
|
package com.yexuejc.springboot.base.security;
|
||||||
|
|
||||||
|
import com.yexuejc.base.pojo.ApiVO;
|
||||||
|
import com.yexuejc.base.util.StrUtil;
|
||||||
|
import com.yexuejc.springboot.base.constant.BizConsts;
|
||||||
|
import com.yexuejc.springboot.base.constant.LogTypeConsts;
|
||||||
|
import com.yexuejc.springboot.base.exception.ThirdPartyAuthorizationException;
|
||||||
|
import com.yexuejc.springboot.base.security.inte.User;
|
||||||
|
import com.yexuejc.springboot.base.security.inte.UserService;
|
||||||
|
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||||
|
import org.springframework.security.crypto.password.*;
|
||||||
|
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>主要做验证用户使用</h2>
|
||||||
|
* <pre>
|
||||||
|
* 密码登录:校验账号密码
|
||||||
|
* 短信登录:校验短信验证码
|
||||||
|
* 第三方登录:校验openid=>用户中心(数据库)不存在,进行新增数据操作
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author maxf
|
||||||
|
* @version 1.0
|
||||||
|
* @ClassName ConsumerAuthenticationProvider
|
||||||
|
* @Description
|
||||||
|
* @date 2018/11/9 11:23
|
||||||
|
*/
|
||||||
|
public class ConsumerAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
|
||||||
|
// ~ Static fields/initializers
|
||||||
|
// =====================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The plaintext password used to perform
|
||||||
|
* PasswordEncoder#matches(CharSequence, String)} on when the user is
|
||||||
|
* not found to avoid SEC-2056.
|
||||||
|
*/
|
||||||
|
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
|
||||||
|
|
||||||
|
// ~ Instance fields
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The password used to perform
|
||||||
|
* {@link PasswordEncoder#matches(CharSequence, String)} on when the user is
|
||||||
|
* not found to avoid SEC-2056. This is necessary, because some
|
||||||
|
* {@link PasswordEncoder} implementations will short circuit if the password is not
|
||||||
|
* in a valid format.
|
||||||
|
*/
|
||||||
|
private volatile String userNotFoundEncodedPassword;
|
||||||
|
|
||||||
|
private UserDetailsService userDetailsService;
|
||||||
|
private final UserService accountView;
|
||||||
|
|
||||||
|
|
||||||
|
public ConsumerAuthenticationProvider(UserDetailsService userDetailsService, UserService accountView) {
|
||||||
|
// super();
|
||||||
|
super.setHideUserNotFoundExceptions(false);
|
||||||
|
// // 这个地方一定要对userDetailsService赋值,不然userDetailsService是null (这个坑有点深)
|
||||||
|
setUserDetailsService(userDetailsService);
|
||||||
|
setPasswordEncoder(createDelegatingPasswordEncoder());
|
||||||
|
this.accountView = accountView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义加密方式
|
||||||
|
* 默认MD5加密
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected PasswordEncoder createDelegatingPasswordEncoder() {
|
||||||
|
String encodingId = "MD5";
|
||||||
|
Map<String, PasswordEncoder> encoders = new HashMap<>(9);
|
||||||
|
encoders.put("bcrypt", new BCryptPasswordEncoder());
|
||||||
|
encoders.put("ldap", new LdapShaPasswordEncoder());
|
||||||
|
encoders.put("MD4", new Md4PasswordEncoder());
|
||||||
|
encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
|
||||||
|
encoders.put("noop", NoOpPasswordEncoder.getInstance());
|
||||||
|
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
|
||||||
|
encoders.put("scrypt", new SCryptPasswordEncoder());
|
||||||
|
encoders.put("SHA-1", new MessageDigestPasswordEncoder("SHA-1"));
|
||||||
|
encoders.put("SHA-256", new MessageDigestPasswordEncoder("SHA-256"));
|
||||||
|
encoders.put("sha256", new StandardPasswordEncoder());
|
||||||
|
return new DelegatingPasswordEncoder(encodingId, encoders);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
|
||||||
|
String requestPwd = authentication.getCredentials().toString();
|
||||||
|
if (authentication instanceof ConsumerToken) {
|
||||||
|
ConsumerToken consumerToken = (ConsumerToken) authentication;
|
||||||
|
|
||||||
|
|
||||||
|
displyAuthenticationChecks(consumerToken, requestPwd, userDetails.getPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录密码校验
|
||||||
|
*
|
||||||
|
* @param consumerToken 登录信息
|
||||||
|
* @param requestPwd 登录密码
|
||||||
|
* @param dbPwd 源用户密码(数据库中的密码)
|
||||||
|
*/
|
||||||
|
protected void displyAuthenticationChecks(ConsumerToken consumerToken, String requestPwd, String dbPwd) {
|
||||||
|
ApiVO apiVO;
|
||||||
|
switch (consumerToken.getLogtype()) {
|
||||||
|
case LogTypeConsts.SMS:
|
||||||
|
//新注册账号已经在注册的时候校验的短信验证码,所有这里不校验
|
||||||
|
if (!consumerToken.isReg) {
|
||||||
|
apiVO = accountView.checkSmsCode2Redis(BizConsts.CONSUMER_LOGIN_SMS, consumerToken.getUsername(), consumerToken.getSmscode());
|
||||||
|
if (apiVO.isFail()) {
|
||||||
|
throw new ThirdPartyAuthorizationException(apiVO.getMsg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LogTypeConsts.QQ:
|
||||||
|
break;
|
||||||
|
case LogTypeConsts.WECHAT:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case LogTypeConsts.WEIBO:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//账号登录
|
||||||
|
if (!passwordEncoder.matches(requestPwd, "{MD5}" + dbPwd)) {
|
||||||
|
logger.debug("Authentication failed: password does not match stored value");
|
||||||
|
|
||||||
|
throw new ThirdPartyAuthorizationException("密码错误");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doAfterPropertiesSet() throws Exception {
|
||||||
|
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final UserDetails retrieveUser(String username,
|
||||||
|
UsernamePasswordAuthenticationToken authentication)
|
||||||
|
throws AuthenticationException {
|
||||||
|
UserDetails loadedUser = null;
|
||||||
|
|
||||||
|
String logtype = "";
|
||||||
|
ConsumerToken consumerToken = null;
|
||||||
|
if (authentication instanceof ConsumerToken) {
|
||||||
|
consumerToken = (ConsumerToken) authentication;
|
||||||
|
logtype = StrUtil.setStr(consumerToken.getLogtype(), "");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
//通过username查询数据库,当第三方登录时所传参数为openid(没有传username),此次会抛出找DB不到账号信息的异常,交给catch处理
|
||||||
|
prepareTimingAttackProtection();
|
||||||
|
loadedUser = this.getUserDetailsService().loadUserByUsername(username);
|
||||||
|
} catch (UsernameNotFoundException notFound) {
|
||||||
|
//账号登录
|
||||||
|
if ((StrUtil.isEmpty(logtype) || LogTypeConsts.ACCOUNT.equals(logtype))) {
|
||||||
|
mitigateAgainstTimingAttack(authentication);
|
||||||
|
throw notFound;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
//其他方式登录:查询账号 没有->创建账号
|
||||||
|
//第三方登录
|
||||||
|
if (consumerToken != null && StrUtil.isNotEmpty(consumerToken.getOpenid())) {
|
||||||
|
ApiVO apiVO = accountView.checkOpenId(consumerToken);
|
||||||
|
if (apiVO.isSucc()) {
|
||||||
|
//已有账号
|
||||||
|
User consumer = apiVO.getObject1(User.class);
|
||||||
|
// 处理用户权限
|
||||||
|
List<GrantedAuthority> authorities = new ArrayList<>();
|
||||||
|
for (String role : consumer.getRoles()) {
|
||||||
|
authorities.add(new SimpleGrantedAuthority(role));
|
||||||
|
}
|
||||||
|
loadedUser = new ConsumerUser(
|
||||||
|
StrUtil.isEmpty(consumer.getMobile()) ? consumerToken.getOpenid() : consumer.getMobile(),
|
||||||
|
consumer.getPwd(), consumer.getEnable(), consumer.getNonExpire(),
|
||||||
|
true, consumer.getNonLock(), authorities, consumer.getConsumerId(),
|
||||||
|
logtype, System.currentTimeMillis());
|
||||||
|
return loadedUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//第三方登录+短信登录
|
||||||
|
if (consumerToken != null) {
|
||||||
|
//没有->创建账号
|
||||||
|
consumerToken.isReg = true;
|
||||||
|
ApiVO apiVO = accountView.addConsumer(consumerToken);
|
||||||
|
if (apiVO.isSucc()) {
|
||||||
|
loadedUser = display(consumerToken, apiVO.getObject1(User.class));
|
||||||
|
return loadedUser;
|
||||||
|
} else {
|
||||||
|
throw new ThirdPartyAuthorizationException(apiVO.getMsg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (e instanceof ThirdPartyAuthorizationException) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
throw new ThirdPartyAuthorizationException("登录失败,请稍后重试");
|
||||||
|
}
|
||||||
|
throw notFound;
|
||||||
|
}
|
||||||
|
} catch (Exception repositoryProblem) {
|
||||||
|
throw new InternalAuthenticationServiceException(
|
||||||
|
repositoryProblem.getMessage(), repositoryProblem);
|
||||||
|
}
|
||||||
|
if (loadedUser == null) {
|
||||||
|
throw new InternalAuthenticationServiceException(
|
||||||
|
"UserDetailsService returned null, which is an interface contract violation");
|
||||||
|
}
|
||||||
|
return loadedUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareTimingAttackProtection() {
|
||||||
|
if (this.userNotFoundEncodedPassword == null) {
|
||||||
|
this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mitigateAgainstTimingAttack(UsernamePasswordAuthenticationToken authentication) {
|
||||||
|
if (authentication.getCredentials() != null) {
|
||||||
|
String presentedPassword = authentication.getCredentials().toString();
|
||||||
|
this.passwordEncoder.matches(presentedPassword, "{MD5}" + this.userNotFoundEncodedPassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理用户为登录用户
|
||||||
|
*
|
||||||
|
* @param consumerToken 登录用户信息
|
||||||
|
* @param consumer 实际用户信息
|
||||||
|
* @return response User
|
||||||
|
*/
|
||||||
|
private UserDetails display(ConsumerToken consumerToken, User consumer) {
|
||||||
|
// 处理用户权限
|
||||||
|
List<GrantedAuthority> authorities = new ArrayList<>();
|
||||||
|
for (String role : consumer.getRoles()) {
|
||||||
|
authorities.add(new SimpleGrantedAuthority(role));
|
||||||
|
}
|
||||||
|
UserDetails userDetails = new ConsumerUser(
|
||||||
|
StrUtil.isEmpty(consumer.getMobile()) ? consumerToken.getOpenid() : consumer.getMobile(),
|
||||||
|
consumer.getPwd(), consumer.getEnable(), consumer.getNonExpire(),
|
||||||
|
true, consumer.getNonLock(), authorities, consumer.getConsumerId(),
|
||||||
|
consumerToken.getLogtype(), System.currentTimeMillis());
|
||||||
|
return userDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the PasswordEncoder instance to be used to encode and validate passwords. If
|
||||||
|
* not set, the password will be compared using {@link PasswordEncoderFactories#createDelegatingPasswordEncoder()}
|
||||||
|
*
|
||||||
|
* @param passwordEncoder must be an instance of one of the {@code PasswordEncoder}
|
||||||
|
* types.
|
||||||
|
*/
|
||||||
|
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
|
||||||
|
Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
|
||||||
|
this.passwordEncoder = passwordEncoder;
|
||||||
|
this.userNotFoundEncodedPassword = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PasswordEncoder getPasswordEncoder() {
|
||||||
|
return passwordEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||||
|
this.userDetailsService = userDetailsService;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected UserDetailsService getUserDetailsService() {
|
||||||
|
return userDetailsService;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,129 @@
|
|||||||
|
package com.yexuejc.springboot.base.security;
|
||||||
|
|
||||||
|
import com.yexuejc.base.constant.RespsConsts;
|
||||||
|
import com.yexuejc.base.util.JwtUtil;
|
||||||
|
import com.yexuejc.springboot.base.constant.BizConsts;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.context.SecurityContextImpl;
|
||||||
|
import org.springframework.security.web.context.HttpRequestResponseHolder;
|
||||||
|
import org.springframework.security.web.context.SecurityContextRepository;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Security 上下文配置
|
||||||
|
* <p>
|
||||||
|
* 校验token=>返回token携带用户(登录用户)信息
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @ClassName: ConsumerSecurityContextRepository
|
||||||
|
* @Description:Security 上下文配置
|
||||||
|
* @author: maxf
|
||||||
|
* @date: 2017年11月22日 下午4:39:20
|
||||||
|
*/
|
||||||
|
public class ConsumerSecurityContextRepository implements SecurityContextRepository {
|
||||||
|
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||||
|
private static final String TOKEN = "token";
|
||||||
|
private static final String ROLES = "roles";
|
||||||
|
|
||||||
|
private final RedisTemplate<Object, Object> redisTemplate0;
|
||||||
|
|
||||||
|
public ConsumerSecurityContextRepository(RedisTemplate<Object, Object> redisTemplate0) {
|
||||||
|
this.redisTemplate0 = redisTemplate0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
|
||||||
|
SecurityContext context = readSecurityContext(requestResponseHolder.getRequest());
|
||||||
|
if (context == null) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("No SecurityContext was available, A new one will be created.");
|
||||||
|
}
|
||||||
|
context = SecurityContextHolder.createEmptyContext();
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the security context on completion of a request.
|
||||||
|
* <p>Title: saveContext</p>
|
||||||
|
* <p>Description:Stores the security context on completion of a request. </p>
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @see SecurityContextRepository#saveContext(SecurityContext, HttpServletRequest, HttpServletResponse)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsContext(HttpServletRequest request) {
|
||||||
|
return readSecurityContext(request) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 过滤登录认证
|
||||||
|
* 默认:header=>Authorization:token
|
||||||
|
* token 为 jwt串
|
||||||
|
* 此处使用登录返回的token解析到具体的登录用户,返回登录用户信息;如果没有,者无权限请求该接口
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
*/
|
||||||
|
protected SecurityContext readSecurityContext(HttpServletRequest request) {
|
||||||
|
final boolean debug = logger.isDebugEnabled();
|
||||||
|
|
||||||
|
String token = request.getHeader(RespsConsts.HEADER_AUTHORIZATION);
|
||||||
|
if (token == null || token.length() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
LoginToken consumerToken = JwtUtil.instace().parse(token, LoginToken.class);
|
||||||
|
if (consumerToken == null || consumerToken.getUsername() == null || consumerToken.getUsername().length() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 根据token中携带的username查询用户信息
|
||||||
|
Map<Object, Object> entry = redisTemplate0.opsForHash()
|
||||||
|
.entries(BizConsts.CONSUMER_LOGIN_REDIS + "." + consumerToken.getUsername());
|
||||||
|
if (entry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!token.equals(entry.get(TOKEN))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 处理用户权限
|
||||||
|
List<GrantedAuthority> authorities = new ArrayList<>();
|
||||||
|
for (String role : (List<String>) entry.get(ROLES)) {
|
||||||
|
authorities.add(new SimpleGrantedAuthority(role));
|
||||||
|
}
|
||||||
|
ConsumerUser consumerUser = new ConsumerUser((String) entry.get("username"), "",
|
||||||
|
true, true, true, true, authorities,
|
||||||
|
(String) entry.get("id"), (String) entry.get("logType"), (Long) entry.get("logTime"));
|
||||||
|
|
||||||
|
SecurityContext context = new SecurityContextImpl();
|
||||||
|
|
||||||
|
consumerUser.eraseCredentials();
|
||||||
|
context.setAuthentication(
|
||||||
|
new UsernamePasswordAuthenticationToken(consumerUser, null, consumerUser.getAuthorities()));
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
logger.debug("Obtained a valid SecurityContext : '" + context + "'");
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,147 @@
|
|||||||
|
package com.yexuejc.springboot.base.security;
|
||||||
|
|
||||||
|
import com.yexuejc.base.util.JsonUtil;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录参数 request <br/>
|
||||||
|
* 用于存放授权后,需要提取的用户信息
|
||||||
|
*
|
||||||
|
* @ClassName: ConsumerToken
|
||||||
|
* @Description: 用于存放授权后,需要提取的用户信息
|
||||||
|
* @author: maxf
|
||||||
|
* @date: 2017年11月22日 下午4:39:29
|
||||||
|
*/
|
||||||
|
public class ConsumerToken extends UsernamePasswordAuthenticationToken {
|
||||||
|
private static final long serialVersionUID = -1923797941L;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费者用户名(手机号)
|
||||||
|
*/
|
||||||
|
private String username;
|
||||||
|
/**
|
||||||
|
* 登录方式
|
||||||
|
*/
|
||||||
|
private String logtype;
|
||||||
|
/**
|
||||||
|
* 短信验证码
|
||||||
|
*/
|
||||||
|
private String smscode;
|
||||||
|
/**
|
||||||
|
* openid
|
||||||
|
*/
|
||||||
|
private String openid;
|
||||||
|
/********************************** 第三方登录时附带信息*************************************/
|
||||||
|
/**
|
||||||
|
* 头像
|
||||||
|
*/
|
||||||
|
private String head;
|
||||||
|
/**
|
||||||
|
* 昵称
|
||||||
|
*/
|
||||||
|
private String nickname;
|
||||||
|
/**
|
||||||
|
* 性别
|
||||||
|
*/
|
||||||
|
private String sex;
|
||||||
|
|
||||||
|
|
||||||
|
/********************************** 第三方登录时附带信息*************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否注册账号:减少sms注册时短信校验次数
|
||||||
|
*/
|
||||||
|
public boolean isReg = false;
|
||||||
|
|
||||||
|
|
||||||
|
public ConsumerToken(String username) {
|
||||||
|
super(null, null);
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConsumerToken(Object principal, Object credentials) {
|
||||||
|
super(principal, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConsumerToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
|
||||||
|
super(principal, credentials, authorities);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConsumerToken(String logtype, String smscode, String openid, String username, Object credentials, String head, String nickname,
|
||||||
|
String sex) {
|
||||||
|
super(username, credentials);
|
||||||
|
this.username = username;
|
||||||
|
this.logtype = logtype;
|
||||||
|
this.smscode = smscode;
|
||||||
|
this.openid = openid;
|
||||||
|
this.head = head;
|
||||||
|
this.nickname = nickname;
|
||||||
|
this.sex = sex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonUtil.obj2Json(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLogtype() {
|
||||||
|
return logtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLogtype(String logtype) {
|
||||||
|
this.logtype = logtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSmscode() {
|
||||||
|
return smscode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSmscode(String smscode) {
|
||||||
|
this.smscode = smscode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOpenid() {
|
||||||
|
return openid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOpenid(String openid) {
|
||||||
|
this.openid = openid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHead() {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHead(String head) {
|
||||||
|
this.head = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNickname() {
|
||||||
|
return nickname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNickname(String nickname) {
|
||||||
|
this.nickname = nickname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSex() {
|
||||||
|
return sex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSex(String sex) {
|
||||||
|
this.sex = sex;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.yexuejc.springboot.base.security;
|
||||||
|
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.User;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录用户信息 response
|
||||||
|
*
|
||||||
|
* @ClassName: ConsumerUser
|
||||||
|
* @Description:登录用户信息
|
||||||
|
* @author: maxf
|
||||||
|
* @date: 2017年11月22日 下午4:39:45
|
||||||
|
*/
|
||||||
|
public class ConsumerUser extends User {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费者用户主键ID
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
/**
|
||||||
|
* 登录方式
|
||||||
|
*/
|
||||||
|
private String logType;
|
||||||
|
/**
|
||||||
|
* 登录时间
|
||||||
|
*/
|
||||||
|
private Long logTime;
|
||||||
|
|
||||||
|
public ConsumerUser(String username, String password, boolean enabled, boolean accountNonExpired,
|
||||||
|
boolean credentialsNonExpired, boolean accountNonLocked,
|
||||||
|
Collection<? extends GrantedAuthority> authorities,
|
||||||
|
String id, String logType, Long logTime) {
|
||||||
|
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
|
||||||
|
this.id = id;
|
||||||
|
this.logType = logType;
|
||||||
|
this.logTime = logTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅做保存登录用户信息时使用
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* @param id
|
||||||
|
* @param logType
|
||||||
|
* @param logTime
|
||||||
|
*/
|
||||||
|
public ConsumerUser(String username, String id, String logType, Long logTime) {
|
||||||
|
super(username, "", true, true, true, true, null);
|
||||||
|
this.id = id;
|
||||||
|
this.logType = logType;
|
||||||
|
this.logTime = logTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(super.toString()).append(": ");
|
||||||
|
|
||||||
|
sb.append("id: ").append(this.id).append("; ");
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLogType() {
|
||||||
|
return logType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLogType(String logType) {
|
||||||
|
this.logType = logType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getLogTime() {
|
||||||
|
return logTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLogTime(Long logTime) {
|
||||||
|
this.logTime = logTime;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.yexuejc.springboot.base.security;
|
||||||
|
|
||||||
|
import com.yexuejc.base.util.JsonUtil;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 封装登录信息至JWT得到token
|
||||||
|
*
|
||||||
|
* @author: maxf
|
||||||
|
* @date: 2018/5/31 21:34
|
||||||
|
*/
|
||||||
|
public class LoginToken implements Serializable {
|
||||||
|
/**
|
||||||
|
* 消费者用户名(手机号)
|
||||||
|
*/
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
public LoginToken() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonUtil.obj2Json(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoginToken(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
package com.yexuejc.springboot.base.security;
|
||||||
|
|
||||||
|
import com.yexuejc.springboot.base.autoconfigure.MutiRedisAutoConfiguration;
|
||||||
|
import com.yexuejc.springboot.base.security.inte.UserService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.config.BeanIds;
|
||||||
|
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.WebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||||
|
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Security Web 配置
|
||||||
|
*
|
||||||
|
* @ClassName: SecurityConfig
|
||||||
|
* @Description:Security Web 配置
|
||||||
|
* @author: maxf
|
||||||
|
* @date: 2017年11月22日 下午4:40:22
|
||||||
|
*/
|
||||||
|
//@EnableWebSecurity(debug = false)
|
||||||
|
public abstract class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
|
||||||
|
@Override
|
||||||
|
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||||
|
return super.authenticationManagerBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier(MutiRedisAutoConfiguration.BEAN_REDIS_TEMPLATE0)
|
||||||
|
private RedisTemplate<Object, Object> redisTemplate0;
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public static NoOpPasswordEncoder passwordEncoder() {
|
||||||
|
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询数据库DB=>获取用户数据loadUserByUsername()
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected abstract UserService getUserService();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
UserDetailsService userDetailsService = new UserDetailsManager(getUserService());
|
||||||
|
auth.authenticationProvider(new ConsumerAuthenticationProvider(userDetailsService, getUserService()));
|
||||||
|
auth.userDetailsService(userDetailsService);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ConsumerAuthenticationProcessingFilter consumerAuthenticationProcessingFilter(
|
||||||
|
AuthenticationManager authenticationManager) throws Exception {
|
||||||
|
ConsumerAuthenticationProcessingFilter filter = new ConsumerAuthenticationProcessingFilter
|
||||||
|
(authenticationManager);
|
||||||
|
filter.setAuthenticationManager(this.authenticationManager());
|
||||||
|
loginHodler(filter);
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 处理登录
|
||||||
|
* 成功: filter.setAuthenticationSuccessHandler()
|
||||||
|
* 失败: filter.setAuthenticationFailureHandler()
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param filter
|
||||||
|
*/
|
||||||
|
protected abstract void loginHodler(ConsumerAuthenticationProcessingFilter filter);
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LoginUrlAuthenticationEntryPoint loginUrlAuthenticationEntryPoint() {
|
||||||
|
LoginUrlAuthenticationEntryPoint loginUrlAuthenticationEntryPoint = new LoginUrlAuthenticationEntryPoint
|
||||||
|
("/login");
|
||||||
|
return loginUrlAuthenticationEntryPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解决跨域问题
|
||||||
|
* <pre>
|
||||||
|
* http.csrf().disable()
|
||||||
|
* .cors()
|
||||||
|
* .and()
|
||||||
|
* </pre>
|
||||||
|
* 参考 https://www.jianshu.com/p/87e1ef68794c -> https://github.com/gothinkster/spring-boot-realworld-example-app
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public CorsConfigurationSource corsConfigurationSource() {
|
||||||
|
final CorsConfiguration configuration = new CorsConfiguration();
|
||||||
|
//指定允许跨域的请求(*所有):http://wap.guansichou.com
|
||||||
|
configuration.setAllowedOrigins(Arrays.asList("*"));
|
||||||
|
configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
|
||||||
|
// setAllowCredentials(true) is important, otherwise:
|
||||||
|
// The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode
|
||||||
|
// is 'include'.
|
||||||
|
configuration.setAllowCredentials(true);
|
||||||
|
// setAllowedHeaders is important! Without it, OPTIONS preflight request
|
||||||
|
// will fail with 403 Invalid CORS request
|
||||||
|
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "X-User-Agent", "Content-Type"));
|
||||||
|
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
|
source.registerCorsConfiguration("/**", configuration);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关键.cors()
|
||||||
|
*
|
||||||
|
* @param http
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http.csrf().disable()
|
||||||
|
.cors()
|
||||||
|
.and().servletApi().disable()
|
||||||
|
.requestCache().disable()
|
||||||
|
.securityContext().securityContextRepository(new ConsumerSecurityContextRepository(redisTemplate0))
|
||||||
|
.and()
|
||||||
|
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||||
|
|
||||||
|
http.addFilterAt(consumerAuthenticationProcessingFilter(super.authenticationManager()),
|
||||||
|
UsernamePasswordAuthenticationFilter.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(WebSecurity web) throws Exception {
|
||||||
|
// 不需要经过SpringSecurity的过滤器的URLs
|
||||||
|
// web.ignoring();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.yexuejc.springboot.base.security;
|
||||||
|
|
||||||
|
import com.yexuejc.base.util.StrUtil;
|
||||||
|
import com.yexuejc.springboot.base.security.inte.User;
|
||||||
|
import com.yexuejc.springboot.base.security.inte.UserService;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConsumerJdbcDaoImpl
|
||||||
|
*
|
||||||
|
* @ClassName: ConsumerJdbcDaoImpl
|
||||||
|
* @Description:ConsumerJdbcDaoImpl
|
||||||
|
* @author: maxf
|
||||||
|
* @date: 2017年12月21日 下午6:17:12
|
||||||
|
*/
|
||||||
|
public class UserDetailsManager extends InMemoryUserDetailsManager {
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
public UserDetailsManager(UserService userService) {
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
|
User consumer = userService.getConsumerByUserName(username);
|
||||||
|
if (StrUtil.isEmpty(consumer)) {
|
||||||
|
throw new UsernameNotFoundException(username);
|
||||||
|
}
|
||||||
|
// 处理用户权限
|
||||||
|
List<GrantedAuthority> authorities = new ArrayList<>();
|
||||||
|
for (String role : consumer.getRoles()) {
|
||||||
|
authorities.add(new SimpleGrantedAuthority(role));
|
||||||
|
}
|
||||||
|
ConsumerUser consumerUser = new ConsumerUser(consumer.getMobile(), consumer.getPwd(),
|
||||||
|
consumer.getEnable(), consumer.getNonExpire(), true, consumer.getNonLock(),
|
||||||
|
authorities, consumer.getConsumerId(), null, System.currentTimeMillis());
|
||||||
|
return consumerUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.yexuejc.springboot.base.security.inte;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author maxf
|
||||||
|
* @version 1.0
|
||||||
|
* @ClassName User
|
||||||
|
* @Description
|
||||||
|
* @date 2018/11/8 17:19
|
||||||
|
*/
|
||||||
|
public interface User {
|
||||||
|
/**
|
||||||
|
* 角色
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<String> getRoles();
|
||||||
|
|
||||||
|
|
||||||
|
String getMobile();
|
||||||
|
|
||||||
|
String getPwd();
|
||||||
|
|
||||||
|
boolean getEnable();
|
||||||
|
|
||||||
|
boolean getNonExpire();
|
||||||
|
|
||||||
|
boolean getNonLock();
|
||||||
|
|
||||||
|
String getConsumerId();
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.yexuejc.springboot.base.security.inte;
|
||||||
|
|
||||||
|
import com.yexuejc.base.pojo.ApiVO;
|
||||||
|
import com.yexuejc.springboot.base.constant.BizConsts;
|
||||||
|
import com.yexuejc.springboot.base.security.ConsumerToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author maxf
|
||||||
|
* @version 1.0
|
||||||
|
* @ClassName UserService
|
||||||
|
* @Description
|
||||||
|
* @date 2018/11/8 17:17
|
||||||
|
*/
|
||||||
|
public interface UserService {
|
||||||
|
/**
|
||||||
|
* 根据用户名到数据库查询用户
|
||||||
|
*
|
||||||
|
* @param username 登录账号
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
User getConsumerByUserName(String username);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验短信验证码=>短信登录
|
||||||
|
*
|
||||||
|
* @param redisBiz {@link BizConsts.CONSUMER_LOGIN_SMS} 业务id reids使用
|
||||||
|
* @param username 登录账号
|
||||||
|
* @param smscode 短信验证码
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ApiVO checkSmsCode2Redis(String redisBiz, String username, String smscode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验第三方登录openid
|
||||||
|
*
|
||||||
|
* @param consumerToken 登录信息
|
||||||
|
* @return apiVO.setObject1(User.class) 自己封装登录用户信息
|
||||||
|
*/
|
||||||
|
ApiVO checkOpenId(ConsumerToken consumerToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 没有账号时根据登录信息创建账号
|
||||||
|
*
|
||||||
|
* @param consumerToken 登录信息
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ApiVO addConsumer(ConsumerToken consumerToken);
|
||||||
|
}
|
@ -2,8 +2,10 @@ package com.yexuejc.springboot.base;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication(exclude = {RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class})
|
||||||
public class ApplicationRun {
|
public class ApplicationRun {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(ApplicationRun.class, args);
|
SpringApplication.run(ApplicationRun.class, args);
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.yexuejc.springboot.base.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||||
|
import com.yexuejc.springboot.base.security.domain.Consumer;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author yexuejc
|
||||||
|
* @since 2018-05-27
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface ConsumerMapper extends BaseMapper<Consumer> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 插入一条记录
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param entity 实体对象
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
int insert(Consumer entity);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改权限
|
||||||
|
*
|
||||||
|
* @param entity
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Integer updateRoles(@Param(Constants.ENTITY) Consumer entity);
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package com.yexuejc.springboot.base.mapper.handler;
|
||||||
|
|
||||||
|
import com.yexuejc.base.util.JsonUtil;
|
||||||
|
import org.apache.ibatis.type.BaseTypeHandler;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
import org.apache.ibatis.type.MappedTypes;
|
||||||
|
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据库查询转换 -> JSON
|
||||||
|
*/
|
||||||
|
@MappedTypes({Object.class})
|
||||||
|
public class JsonTypeHandler extends BaseTypeHandler<Object> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
|
||||||
|
throws SQLException {
|
||||||
|
if (parameter == null) {
|
||||||
|
ps.setString(i, null);
|
||||||
|
} else {
|
||||||
|
ps.setString(i, JsonUtil.obj2Json(parameter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||||
|
if (rs.getString(columnName) == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JsonUtil.json2Obj(rs.getString(columnName), Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||||
|
if (rs.getString(columnIndex) == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JsonUtil.json2Obj(rs.getString(columnIndex), Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||||
|
if (cs.getString(columnIndex) == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JsonUtil.json2Obj(cs.getString(columnIndex), Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,184 @@
|
|||||||
|
package com.yexuejc.springboot.base.security;
|
||||||
|
|
||||||
|
import com.yexuejc.base.constant.RespsConsts;
|
||||||
|
import com.yexuejc.base.http.Resps;
|
||||||
|
import com.yexuejc.base.util.JsonUtil;
|
||||||
|
import com.yexuejc.base.util.JwtUtil;
|
||||||
|
import com.yexuejc.base.util.RegexUtil;
|
||||||
|
import com.yexuejc.base.util.StrUtil;
|
||||||
|
import com.yexuejc.springboot.base.autoconfigure.MutiRedisAutoConfiguration;
|
||||||
|
import com.yexuejc.springboot.base.constant.BizConsts;
|
||||||
|
import com.yexuejc.springboot.base.exception.ThirdPartyAuthorizationException;
|
||||||
|
import com.yexuejc.springboot.base.security.inte.UserService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.authentication.*;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author maxf
|
||||||
|
* @version 1.0
|
||||||
|
* @ClassName SecurityConfig
|
||||||
|
* @Description
|
||||||
|
* @date 2018/11/8 17:30
|
||||||
|
*/
|
||||||
|
@EnableWebSecurity(debug = false)
|
||||||
|
public class MySecurityConfig extends SecurityConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("userserviceimpl")
|
||||||
|
UserService userService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected UserService getUserService() {
|
||||||
|
return userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier(MutiRedisAutoConfiguration.BEAN_REDIS_TEMPLATE0)
|
||||||
|
private RedisTemplate<Object, Object> redisTemplate0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存登录信息至redis
|
||||||
|
*
|
||||||
|
* @param redisTemplate0 redis 链接
|
||||||
|
* @param user 登录用户
|
||||||
|
* @param roles 角色信息
|
||||||
|
* @param token 登录token
|
||||||
|
* @param isPast 是否设置过期
|
||||||
|
*/
|
||||||
|
private void saveLoginUser(RedisTemplate<Object, Object> redisTemplate0, ConsumerUser user, List<String> roles, String token,
|
||||||
|
boolean isPast) {
|
||||||
|
Map<String, Object> m = new HashMap<>(4);
|
||||||
|
m.put("username", user.getUsername());
|
||||||
|
m.put("token", token);
|
||||||
|
m.put("roles", roles);
|
||||||
|
m.put("id", user.getId());
|
||||||
|
m.put("logType", user.getLogType());
|
||||||
|
m.put("logTime", user.getLogTime());
|
||||||
|
redisTemplate0.opsForHash().putAll(BizConsts.CONSUMER_LOGIN_REDIS + "." + user.getUsername(), m);
|
||||||
|
if (isPast) {
|
||||||
|
//对于没有绑定手机号的token,10分钟后过期
|
||||||
|
redisTemplate0.expire(BizConsts.CONSUMER_LOGIN_REDIS + "." + user.getUsername(), 10, TimeUnit.MINUTES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 处理登录
|
||||||
|
* 成功: filter.setAuthenticationSuccessHandler()
|
||||||
|
* 失败: filter.setAuthenticationFailureHandler()
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param filter
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void loginHodler(ConsumerAuthenticationProcessingFilter filter) {
|
||||||
|
filter.setAuthenticationSuccessHandler((request, response, authentication) -> {
|
||||||
|
String token = JwtUtil.instace().compact(new LoginToken(authentication.getName()));
|
||||||
|
ConsumerUser user = (ConsumerUser) authentication.getPrincipal();
|
||||||
|
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
|
||||||
|
List<String> roles = new ArrayList<>();
|
||||||
|
if (authorities != null && authorities.size() > 0) {
|
||||||
|
for (GrantedAuthority g : authorities) {
|
||||||
|
roles.add(g.getAuthority());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<String, Object> map = new HashMap<>(2);
|
||||||
|
map.put("token", token);
|
||||||
|
map.put("bindMobile", false);
|
||||||
|
if (StrUtil.isEmpty(user.getUsername()) || !RegexUtil.regex(user.getUsername(), RegexUtil.REGEX_MOBILE)) {
|
||||||
|
map.put("bindMobile", true);
|
||||||
|
}
|
||||||
|
saveLoginUser(redisTemplate0, user, roles, token, (Boolean) map.get("bindMobile"));
|
||||||
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
|
response.getWriter().write(JsonUtil.obj2Json(Resps.success().setSucc(map)));
|
||||||
|
response.getWriter().close();
|
||||||
|
});
|
||||||
|
filter.setAuthenticationFailureHandler((request, response, exception) -> {
|
||||||
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
|
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||||
|
Resps resps = new Resps();
|
||||||
|
if (exception instanceof DisabledException) {
|
||||||
|
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_IS_LOCK_MSG});
|
||||||
|
} else if (exception instanceof AccountExpiredException) {
|
||||||
|
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_IS_EXPIRE_MSG});
|
||||||
|
} else if (exception instanceof CredentialsExpiredException) {
|
||||||
|
resps.setErr(BizConsts.BASE_LOGIN_IS_EXPIRE_CODE, new String[]{BizConsts.BASE_LOGIN_IS_EXPIRE_MSG});
|
||||||
|
} else if (exception instanceof LockedException) {
|
||||||
|
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_IS_LOCKED_MSG});
|
||||||
|
} else if (exception instanceof AuthenticationCredentialsNotFoundException) {
|
||||||
|
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_CREDENTIALS_NOT_FOUND_MSG});
|
||||||
|
} else if (exception instanceof ThirdPartyAuthorizationException) {
|
||||||
|
resps.setErr(RespsConsts.CODE_FAIL, new String[]{exception.getMessage()});
|
||||||
|
} else if (exception instanceof BadCredentialsException) {
|
||||||
|
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_PWD_IS_ERR_MSG});
|
||||||
|
} else if (exception instanceof UsernameNotFoundException) {
|
||||||
|
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_ACCOUNT_NOT_FOUND_MSG});
|
||||||
|
} else {
|
||||||
|
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_SYS_ERR_MSG});
|
||||||
|
}
|
||||||
|
response.getWriter().write(JsonUtil.obj2Json(resps));
|
||||||
|
response.getWriter().close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
super.configure(http);
|
||||||
|
http.headers().frameOptions().disable();
|
||||||
|
/**
|
||||||
|
* 权限控制
|
||||||
|
* ->无权限
|
||||||
|
*/
|
||||||
|
http.authorizeRequests().antMatchers(
|
||||||
|
"/", "/index"
|
||||||
|
).permitAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限控制
|
||||||
|
* ->登录可访问
|
||||||
|
*/
|
||||||
|
http.authorizeRequests().antMatchers(
|
||||||
|
"/consumer/**", "/sms/bind/**").authenticated();
|
||||||
|
|
||||||
|
// 登出处理。
|
||||||
|
http.logout().logoutSuccessHandler((request, response, authentication) -> {
|
||||||
|
redisTemplate0.delete(BizConsts.CONSUMER_LOGIN_REDIS + "." + authentication.getName());
|
||||||
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
|
response.getWriter().write(JsonUtil.obj2Json(Resps.success()));
|
||||||
|
response.getWriter().close();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 未登录,却访问需要登录的接口时的处理
|
||||||
|
http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
|
||||||
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
|
response.setStatus(401);
|
||||||
|
response.getWriter().write(
|
||||||
|
JsonUtil.obj2Json(
|
||||||
|
Resps.error(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_NOT_LOGIN_MSG})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
response.getWriter().close();
|
||||||
|
});
|
||||||
|
// 已登录,但当前用户没有访问的某个接口的权限时的处理
|
||||||
|
http.exceptionHandling().accessDeniedHandler((request, response, accessDeniedException) -> {
|
||||||
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
|
response.setStatus(401);
|
||||||
|
response.getWriter().write(
|
||||||
|
JsonUtil.obj2Json(
|
||||||
|
Resps.error(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_NOT_ROLE_MSG})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
response.getWriter().close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,337 @@
|
|||||||
|
package com.yexuejc.springboot.base.security;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
|
import com.yexuejc.base.constant.RespsConsts;
|
||||||
|
import com.yexuejc.base.pojo.ApiVO;
|
||||||
|
import com.yexuejc.base.util.StrUtil;
|
||||||
|
import com.yexuejc.springboot.base.autoconfigure.MutiRedisAutoConfiguration;
|
||||||
|
import com.yexuejc.springboot.base.constant.BizConsts;
|
||||||
|
import com.yexuejc.springboot.base.constant.DictRegTypeConsts;
|
||||||
|
import com.yexuejc.springboot.base.constant.LogTypeConsts;
|
||||||
|
import com.yexuejc.springboot.base.exception.ThirdPartyAuthorizationException;
|
||||||
|
import com.yexuejc.springboot.base.mapper.ConsumerMapper;
|
||||||
|
import com.yexuejc.springboot.base.security.domain.Consumer;
|
||||||
|
import com.yexuejc.springboot.base.security.inte.User;
|
||||||
|
import com.yexuejc.springboot.base.security.inte.UserService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据库操作DB
|
||||||
|
*
|
||||||
|
* @author maxf
|
||||||
|
* @version 1.0
|
||||||
|
* @ClassName UserServiceImpl
|
||||||
|
* @Description
|
||||||
|
* @date 2018/11/8 17:31
|
||||||
|
*/
|
||||||
|
@Service("userserviceimpl")
|
||||||
|
public class UserServiceImpl implements UserService {
|
||||||
|
@Autowired
|
||||||
|
ConsumerMapper consumerMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier(MutiRedisAutoConfiguration.BEAN_REDIS_TEMPLATE1)
|
||||||
|
private RedisTemplate<Object, Object> redisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户名到数据库查询用户
|
||||||
|
*
|
||||||
|
* @param username 登录账号
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public User getConsumerByUserName(String username) {
|
||||||
|
QueryWrapper queryWrapper = new QueryWrapper();
|
||||||
|
queryWrapper.eq("mobile", username);
|
||||||
|
Consumer consumer = consumerMapper.selectOne(queryWrapper);
|
||||||
|
return consumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 到自己的reids里面校验短信验证码
|
||||||
|
*
|
||||||
|
* @param smsType {@linkplain BizConsts.CONSUMER_LOGIN_SMS} 业务id reids使用
|
||||||
|
* @param mobile 登录账号
|
||||||
|
* @param code 短信验证码
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ApiVO checkSmsCode2Redis(String smsType, String mobile, String code) {
|
||||||
|
redisTemplate.afterPropertiesSet();
|
||||||
|
String rCode = (String) redisTemplate.opsForHash().get(smsType + "." + mobile, "code");
|
||||||
|
Integer validatedNums = (Integer) redisTemplate.opsForHash().get(smsType + "." + mobile, "validatedNums");
|
||||||
|
if (validatedNums == null) {
|
||||||
|
return new ApiVO(ApiVO.STATUS.F, RespsConsts.CODE_FAIL, "验证码过期,请重新获取");
|
||||||
|
} else if (validatedNums > 5) {
|
||||||
|
redisTemplate.delete(smsType + "." + mobile);
|
||||||
|
return new ApiVO(ApiVO.STATUS.F, RespsConsts.CODE_FAIL, "验证码过期,请重新获取");
|
||||||
|
}
|
||||||
|
if (code.equals(rCode)) {
|
||||||
|
redisTemplate.delete(smsType + "." + mobile);
|
||||||
|
return new ApiVO(ApiVO.STATUS.S);
|
||||||
|
} else {
|
||||||
|
validatedNums++;
|
||||||
|
redisTemplate.opsForHash().put(smsType + "." + mobile, "validatedNums", validatedNums);
|
||||||
|
return new ApiVO(ApiVO.STATUS.F, RespsConsts.CODE_FAIL, "验证码不正确");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验openid 根据自己业务做判断
|
||||||
|
* <br/>
|
||||||
|
* 返回:封装登录用户信息到 apiVO.setObject1(User.class) 自己封装登录用户信息
|
||||||
|
*
|
||||||
|
* @param consumerToken 登录信息
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ApiVO checkOpenId(ConsumerToken consumerToken) {
|
||||||
|
ApiVO apiVO = new ApiVO(ApiVO.STATUS.F, "没有找到用户信息");
|
||||||
|
switch (consumerToken.getLogtype()) {
|
||||||
|
case LogTypeConsts.QQ:
|
||||||
|
apiVO = checkOpenid4QQ(consumerToken, true);
|
||||||
|
break;
|
||||||
|
case LogTypeConsts.WECHAT:
|
||||||
|
apiVO = checkOpenid4Wechat(consumerToken, true);
|
||||||
|
break;
|
||||||
|
case LogTypeConsts.WEIBO:
|
||||||
|
apiVO = checkOpenid4Weibo(consumerToken, true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return apiVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方登录 QQ登录
|
||||||
|
*
|
||||||
|
* @param consumerToken 登录信息
|
||||||
|
* @param b
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ApiVO checkOpenid4QQ(ConsumerToken consumerToken, boolean b) {
|
||||||
|
Consumer consumer = getConsumerByQQOpenid(consumerToken.getOpenid());
|
||||||
|
if (consumer == null) {
|
||||||
|
return new ApiVO(ApiVO.STATUS.F, "获取用户信息失败");
|
||||||
|
}
|
||||||
|
if (b && DictRegTypeConsts.DICT_QQ.equals(consumer.getRegType())) {
|
||||||
|
//如果是qq注册的,登录的同时更新用户信息
|
||||||
|
updateConsumer(consumer, consumerToken);
|
||||||
|
}
|
||||||
|
return new ApiVO(ApiVO.STATUS.S).setObject1(consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方登录 微信登录
|
||||||
|
*
|
||||||
|
* @param consumerToken 登录信息
|
||||||
|
* @param b
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ApiVO checkOpenid4Wechat(ConsumerToken consumerToken, boolean b) {
|
||||||
|
Consumer consumer = getConsumerByWechatOpenid(consumerToken.getOpenid());
|
||||||
|
if (consumer == null) {
|
||||||
|
return new ApiVO(ApiVO.STATUS.F, "获取用户信息失败");
|
||||||
|
}
|
||||||
|
if (b && DictRegTypeConsts.DICT_WECHAT.equals(consumer.getRegType())) {
|
||||||
|
//如果是微信注册的,登录的同时更新用户信息
|
||||||
|
updateConsumer(consumer, consumerToken);
|
||||||
|
}
|
||||||
|
return new ApiVO(ApiVO.STATUS.S).setObject1(consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方登录 微博登录
|
||||||
|
*
|
||||||
|
* @param consumerToken 登录信息
|
||||||
|
* @param b
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ApiVO checkOpenid4Weibo(ConsumerToken consumerToken, boolean b) {
|
||||||
|
Consumer consumer = getConsumerByWeiboOpenid(consumerToken.getOpenid());
|
||||||
|
if (consumer == null) {
|
||||||
|
return new ApiVO(ApiVO.STATUS.F, "获取用户信息失败");
|
||||||
|
}
|
||||||
|
if (b && DictRegTypeConsts.DICT_WEIBO.equals(consumer.getRegType())) {
|
||||||
|
//如果是微博注册的,登录的同时更新用户信息
|
||||||
|
updateConsumer(consumer, consumerToken);
|
||||||
|
}
|
||||||
|
return new ApiVO(ApiVO.STATUS.S).setObject1(consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 没有账号时处理自己的业务,此次必须返回 构造出的登录用户,否则会抛出{@link ThirdPartyAuthorizationException 第三方授权异常}
|
||||||
|
* <br/>
|
||||||
|
* 返回:封装登录用户信息到 apiVO.setObject1(User.class) 自己封装登录用户信息
|
||||||
|
*
|
||||||
|
* @param consumerToken 登录信息
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ApiVO addConsumer(ConsumerToken consumerToken) {
|
||||||
|
Consumer consumer = new Consumer();
|
||||||
|
consumer.setConsumerId(StrUtil.genUUID());
|
||||||
|
consumer.setMobile(StrUtil.isNotEmpty(consumerToken.getUsername()) ? consumerToken.getUsername() : consumerToken.getOpenid());
|
||||||
|
consumer.setPwd(StrUtil.toMD5("123456"));
|
||||||
|
consumer.setEnable(true);
|
||||||
|
consumer.setNonExpire(true);
|
||||||
|
consumer.setNonLock(true);
|
||||||
|
List<String> roles = new ArrayList<>();
|
||||||
|
roles.add("ROLE_CONSUMER");
|
||||||
|
consumer.setRoles(roles);
|
||||||
|
switch (consumerToken.getLogtype()) {
|
||||||
|
case LogTypeConsts.SMS:
|
||||||
|
ApiVO apiVO = checkSmsCode2Redis(BizConsts.CONSUMER_LOGIN_SMS, consumerToken.getUsername(),
|
||||||
|
consumerToken.getSmscode());
|
||||||
|
if (apiVO.isFail()) {
|
||||||
|
return apiVO;
|
||||||
|
}
|
||||||
|
consumer.setNickname(consumerToken.getUsername());
|
||||||
|
consumer.setHead("/head/def.png");
|
||||||
|
consumer.setRegType(DictRegTypeConsts.DICT_MOBILE);
|
||||||
|
break;
|
||||||
|
case LogTypeConsts.QQ:
|
||||||
|
consumer.setQqId(consumerToken.getOpenid());
|
||||||
|
consumer.setNickname(consumerToken.getNickname());
|
||||||
|
setHeader(consumerToken, consumer, false);
|
||||||
|
setSex(consumerToken, consumer);
|
||||||
|
consumer.setRegType(DictRegTypeConsts.DICT_QQ);
|
||||||
|
break;
|
||||||
|
case LogTypeConsts.WECHAT:
|
||||||
|
consumer.setWechatId(consumerToken.getOpenid());
|
||||||
|
consumer.setNickname(consumerToken.getNickname());
|
||||||
|
setHeader(consumerToken, consumer, false);
|
||||||
|
setSex(consumerToken, consumer);
|
||||||
|
consumer.setRegType(DictRegTypeConsts.DICT_WECHAT);
|
||||||
|
break;
|
||||||
|
case LogTypeConsts.WEIBO:
|
||||||
|
consumer.setWeiboId(consumerToken.getOpenid());
|
||||||
|
consumer.setNickname(consumerToken.getNickname());
|
||||||
|
setHeader(consumerToken, consumer, false);
|
||||||
|
setSex(consumerToken, consumer);
|
||||||
|
consumer.setRegType(DictRegTypeConsts.DICT_WEIBO);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new ApiVO(ApiVO.STATUS.F, "暂不支持的登录方式");
|
||||||
|
}
|
||||||
|
Integer result = consumerMapper.insert(consumer);
|
||||||
|
if (result < 1) {
|
||||||
|
return new ApiVO(ApiVO.STATUS.F, RespsConsts.CODE_FAIL, "登录失败");
|
||||||
|
}
|
||||||
|
return new ApiVO(ApiVO.STATUS.S).setObject1(consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Consumer getConsumerByQQOpenid(String openid) {
|
||||||
|
QueryWrapper queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("qq_id", openid);
|
||||||
|
Consumer consumer = consumerMapper.selectOne(queryWrapper);
|
||||||
|
return consumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer getConsumerByWechatOpenid(String openid) {
|
||||||
|
QueryWrapper queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("wechat_id", openid);
|
||||||
|
Consumer consumer = consumerMapper.selectOne(queryWrapper);
|
||||||
|
return consumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer getConsumerByWeiboOpenid(String openid) {
|
||||||
|
QueryWrapper queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("weibo_id", openid);
|
||||||
|
Consumer consumer = consumerMapper.selectOne(queryWrapper);
|
||||||
|
return consumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新基本信息
|
||||||
|
*
|
||||||
|
* @param consumer
|
||||||
|
* @param consumerToken
|
||||||
|
*/
|
||||||
|
private void updateConsumer(Consumer consumer, ConsumerToken consumerToken) {
|
||||||
|
boolean b1, b2, b3;
|
||||||
|
b1 = b2 = b3 = true;
|
||||||
|
if (StrUtil.isNotEmpty(consumerToken.getNickname())) {
|
||||||
|
if (consumerToken.getNickname().equals(consumer.getNickname())) {
|
||||||
|
b1 = false;
|
||||||
|
}
|
||||||
|
consumer.setNickname(consumerToken.getNickname());
|
||||||
|
}
|
||||||
|
b2 = setHeader(consumerToken, consumer, true);
|
||||||
|
b3 = setSex(consumerToken, consumer);
|
||||||
|
if (!b1 && !b2 && !b3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LambdaUpdateWrapper<Consumer> queryWrapper = new UpdateWrapper<>(new Consumer()).lambda();
|
||||||
|
try {
|
||||||
|
queryWrapper.set(Consumer::getNickname, consumer.getNickname())
|
||||||
|
.set(Consumer::getHead, consumer.getHead())
|
||||||
|
.set(Consumer::getSex, consumer.getSex())
|
||||||
|
.eq(Consumer::getConsumerId, consumer.getConsumerId());
|
||||||
|
consumerMapper.update(new Consumer(), queryWrapper);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置头像->上传网络图片到OSS
|
||||||
|
*
|
||||||
|
* @param consumerToken
|
||||||
|
* @param consumer
|
||||||
|
* @param isUpdate
|
||||||
|
*/
|
||||||
|
private boolean setHeader(ConsumerToken consumerToken, Consumer consumer, boolean isUpdate) {
|
||||||
|
if (StrUtil.isNotEmpty(consumerToken.getHead())) {
|
||||||
|
if (isUpdate) {
|
||||||
|
if (consumerToken.getHead().equals(consumer.getSourceHead())) {
|
||||||
|
//未改变头像
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
consumer.setSourceHead(consumerToken.getHead());
|
||||||
|
}
|
||||||
|
//应该上传至OSS后返回OSS地址
|
||||||
|
consumer.setHead(consumerToken.getHead());
|
||||||
|
// try {
|
||||||
|
// consumer.setHead(putOss4Head(null, consumerToken.getHead()));
|
||||||
|
// } catch (ImageException e) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置性别
|
||||||
|
*
|
||||||
|
* @param consumerToken
|
||||||
|
* @param consumer
|
||||||
|
*/
|
||||||
|
private boolean setSex(ConsumerToken consumerToken, Consumer consumer) {
|
||||||
|
if (StrUtil.isNotEmpty(consumerToken.getSex())) {
|
||||||
|
if ("1".equals(consumerToken.getSex()) && !"男".equals(consumer.getSex())) {
|
||||||
|
consumer.setSex("男");
|
||||||
|
return true;
|
||||||
|
} else if ("2".equals(consumerToken.getSex()) && !"女".equals(consumer.getSex())) {
|
||||||
|
consumer.setSex("女");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,281 @@
|
|||||||
|
package com.yexuejc.springboot.base.security.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||||
|
import com.yexuejc.base.util.JsonUtil;
|
||||||
|
import com.yexuejc.springboot.base.security.inte.User;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* <p>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author yexuejc
|
||||||
|
* @since 2018-05-27
|
||||||
|
*/
|
||||||
|
@TableName(resultMap = "BaseResultMap")
|
||||||
|
public class Consumer extends Model<Consumer> implements User {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
@TableId(value = "consumer_id", type = IdType.UUID)
|
||||||
|
private String consumerId;
|
||||||
|
/**
|
||||||
|
* 手机号
|
||||||
|
*/
|
||||||
|
@TableField("mobile")
|
||||||
|
private String mobile;
|
||||||
|
/**
|
||||||
|
* 密码:md5
|
||||||
|
*/
|
||||||
|
@TableField("pwd")
|
||||||
|
private String pwd;
|
||||||
|
/**
|
||||||
|
* 账号是否启用
|
||||||
|
*/
|
||||||
|
@TableField("is_enable")
|
||||||
|
private boolean enable;
|
||||||
|
/**
|
||||||
|
* 账号是否没有过期
|
||||||
|
*/
|
||||||
|
@TableField("is_non_expire")
|
||||||
|
private boolean nonExpire;
|
||||||
|
/**
|
||||||
|
* 账号是否没有被锁定
|
||||||
|
*/
|
||||||
|
@TableField("is_non_lock")
|
||||||
|
private boolean nonLock;
|
||||||
|
/**
|
||||||
|
* 微信id
|
||||||
|
*/
|
||||||
|
@TableField("wechat_id")
|
||||||
|
private String wechatId;
|
||||||
|
/**
|
||||||
|
* qq id
|
||||||
|
*/
|
||||||
|
@TableField("qq_id")
|
||||||
|
private String qqId;
|
||||||
|
/**
|
||||||
|
* 微博id
|
||||||
|
*/
|
||||||
|
@TableField("weibo_id")
|
||||||
|
private String weiboId;
|
||||||
|
/**
|
||||||
|
* 昵称
|
||||||
|
*/
|
||||||
|
@TableField("nickname")
|
||||||
|
private String nickname;
|
||||||
|
/**
|
||||||
|
* 用户头像
|
||||||
|
*/
|
||||||
|
@TableField("head")
|
||||||
|
private String head;
|
||||||
|
/**
|
||||||
|
* 用户邮箱
|
||||||
|
*/
|
||||||
|
@TableField("email")
|
||||||
|
private String email;
|
||||||
|
/**
|
||||||
|
* 用户姓别 '男',‘女’
|
||||||
|
*/
|
||||||
|
@TableField("sex")
|
||||||
|
private String sex;
|
||||||
|
/**
|
||||||
|
* 角色、权限
|
||||||
|
*/
|
||||||
|
@TableField(value = "roles", el = "roles,typeHandler=com.yexuejc.guansc.core.mybatis.handler.JsonTypeHandler")
|
||||||
|
private List<String> roles;
|
||||||
|
/**
|
||||||
|
* 支付密码
|
||||||
|
*/
|
||||||
|
@TableField("pay_pwd")
|
||||||
|
private String payPwd;
|
||||||
|
/**
|
||||||
|
* 注册方式
|
||||||
|
*/
|
||||||
|
@TableField("reg_type")
|
||||||
|
private String regType;
|
||||||
|
/**
|
||||||
|
* 第三方源头像路径
|
||||||
|
*/
|
||||||
|
@TableField("source_head")
|
||||||
|
private String sourceHead;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonUtil.obj2Json(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConsumerId() {
|
||||||
|
return consumerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setConsumerId(String consumerId) {
|
||||||
|
this.consumerId = consumerId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMobile() {
|
||||||
|
return mobile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setMobile(String mobile) {
|
||||||
|
this.mobile = mobile;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPwd() {
|
||||||
|
return pwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getEnable() {
|
||||||
|
return this.enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getNonExpire() {
|
||||||
|
return this.nonExpire;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getNonLock() {
|
||||||
|
return this.nonLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setPwd(String pwd) {
|
||||||
|
this.pwd = pwd;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Consumer setEnable(boolean enable) {
|
||||||
|
this.enable = enable;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Consumer setNonExpire(boolean nonExpire) {
|
||||||
|
this.nonExpire = nonExpire;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Consumer setNonLock(boolean nonLock) {
|
||||||
|
this.nonLock = nonLock;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWechatId() {
|
||||||
|
return wechatId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setWechatId(String wechatId) {
|
||||||
|
this.wechatId = wechatId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQqId() {
|
||||||
|
return qqId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setQqId(String qqId) {
|
||||||
|
this.qqId = qqId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWeiboId() {
|
||||||
|
return weiboId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setWeiboId(String weiboId) {
|
||||||
|
this.weiboId = weiboId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNickname() {
|
||||||
|
return nickname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setNickname(String nickname) {
|
||||||
|
this.nickname = nickname;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHead() {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setHead(String head) {
|
||||||
|
this.head = head;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSex() {
|
||||||
|
return sex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setSex(String sex) {
|
||||||
|
this.sex = sex;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getRoles() {
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setRoles(List<String> roles) {
|
||||||
|
this.roles = roles;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayPwd() {
|
||||||
|
return payPwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setPayPwd(String payPwd) {
|
||||||
|
this.payPwd = payPwd;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRegType() {
|
||||||
|
return regType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setRegType(String regType) {
|
||||||
|
this.regType = regType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceHead() {
|
||||||
|
return sourceHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer setSourceHead(String sourceHead) {
|
||||||
|
this.sourceHead = sourceHead;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Serializable pkVal() {
|
||||||
|
return this.consumerId;
|
||||||
|
}
|
||||||
|
}
|
@ -94,4 +94,5 @@ public class IndexCtrl {
|
|||||||
return Resps.success().setSucc(map);
|
return Resps.success().setSucc(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.yexuejc.springboot.base.web;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* Security 登录注册相关controller
|
||||||
|
* 主要实现
|
||||||
|
* 1.短信登录发送验证码
|
||||||
|
* 2.第三方登录绑定手机号(以及绑定手机号发送验证码)
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author maxf
|
||||||
|
* @version 1.0
|
||||||
|
* @ClassName SecurityCtrl
|
||||||
|
* @Description
|
||||||
|
* @date 2018/11/9 10:52
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class SecurityCtrl {
|
||||||
|
|
||||||
|
}
|
@ -1,38 +1,36 @@
|
|||||||
server.port=8888
|
server.port=8888
|
||||||
|
|
||||||
spring.application.name=@pom.artifactId@
|
spring.application.name=@pom.artifactId@
|
||||||
|
|
||||||
|
#log
|
||||||
logging.level.root=info
|
logging.level.root=info
|
||||||
logging.path=/logs/yexuejc-springboot-parent
|
logging.path=/logs/yexuejc-springboot-parent
|
||||||
|
|
||||||
|
|
||||||
yexuejc.http.filter.type=0
|
yexuejc.http.filter.type=1
|
||||||
|
|
||||||
|
|
||||||
yexuejc.http.encrypt.encrypt=true
|
yexuejc.http.encrypt.encrypt=true
|
||||||
yexuejc.http.encrypt.decrypt=true
|
yexuejc.http.encrypt.decrypt=true
|
||||||
#配置密钥方式
|
#配置密钥方式
|
||||||
#yexuejc.http.encrypt.private-key=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAiSo5blJ9-QJ0_QElcy5AaRTq-3oO4lJ8PvIOIt-Xr5SUFODVj3DUbiy6_0bxQYO3NiYHlXPb37UVV3jjlXJsXwIDAQABAkBE0WOJH2hGs93gRl_0vwLf9ffDfkTTdlER_73p70aad3QZRslEkinQH7G5aE_DgBm5m72TCeH-PD2FZ2lwtavBAiEAvnRown5Lpqbl0tN_OUxr_e1u9d_-8dNL_JEETO7BZCECIQC4XtY-18j0bVVLxaXPjKQ00D59yntwObihDNyRK0nAfwIgHPHEGgrnpGQo-Wl7JFIg925mNqfcLxRVsAS6CpcefQECIQCUsLdsmy6QIhTmNRJSXoSXq1KatE_05DhIekzwLs8eFQIgfMawMiu52ZxBI5_pZ7ancQZ6Dsxl45utFqJShzV1pio
|
#yexuejc.http.encrypt.private-key=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAiSo5blJ9-QJ0_QElcy5AaRTq-3oO4lJ8PvIOIt-Xr5SUFODVj3DUbiy6_0bxQYO3NiYHlXPb37UVV3jjlXJsXwIDAQABAkBE0WOJH2hGs93gRl_0vwLf9ffDfkTTdlER_73p70aad3QZRslEkinQH7G5aE_DgBm5m72TCeH-PD2FZ2lwtavBAiEAvnRown5Lpqbl0tN_OUxr_e1u9d_-8dNL_JEETO7BZCECIQC4XtY-18j0bVVLxaXPjKQ00D59yntwObihDNyRK0nAfwIgHPHEGgrnpGQo-Wl7JFIg925mNqfcLxRVsAS6CpcefQECIQCUsLdsmy6QIhTmNRJSXoSXq1KatE_05DhIekzwLs8eFQIgfMawMiu52ZxBI5_pZ7ancQZ6Dsxl45utFqJShzV1pio
|
||||||
#yexuejc.http.encrypt.public-key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIkqOW5SffkCdP0BJXMuQGkU6vt6DuJSfD7yDiLfl6-UlBTg1Y9w1G4suv9G8UGDtzYmB5Vz29-1FVd445VybF8CAwEAAQ
|
#yexuejc.http.encrypt.public-key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIkqOW5SffkCdP0BJXMuQGkU6vt6DuJSfD7yDiLfl6-UlBTg1Y9w1G4suv9G8UGDtzYmB5Vz29-1FVd445VybF8CAwEAAQ
|
||||||
#配置证书方式
|
#配置证书方式
|
||||||
yexuejc.http.encrypt.private-key-path=/lgfishing.keystore
|
yexuejc.http.encrypt.private-key-path=/lgfishing.keystore
|
||||||
yexuejc.http.encrypt.private-alias=lgfishing
|
yexuejc.http.encrypt.private-alias=lgfishing
|
||||||
yexuejc.http.encrypt.private-pwd=lgfishing2018
|
yexuejc.http.encrypt.private-pwd=lgfishing2018
|
||||||
|
|
||||||
|
|
||||||
#编码
|
#编码
|
||||||
spring.http.encoding.force=true
|
spring.http.encoding.force=true
|
||||||
spring.http.encoding.charset=UTF-8
|
spring.http.encoding.charset=UTF-8
|
||||||
spring.http.encoding.enabled=true
|
spring.http.encoding.enabled=true
|
||||||
server.tomcat.uri-encoding=UTF-8
|
server.tomcat.uri-encoding=UTF-8
|
||||||
|
|
||||||
#是否开启HTTPS(SSL)请求证书验证忽略:默认false
|
#是否开启HTTPS(SSL)请求证书验证忽略:默认false
|
||||||
yexuejc.enable.ssl-ignore=true
|
yexuejc.enable.ssl-ignore=true
|
||||||
|
|
||||||
#reids
|
|
||||||
spring.redis.host=121.42.165.89
|
|
||||||
spring.redis.password=
|
|
||||||
spring.redis.port=16379
|
|
||||||
|
|
||||||
|
|
||||||
#mns
|
#mns
|
||||||
@ -46,3 +44,50 @@ yexuejc.alibaba.oss.endpoint=oss-cn-beijing.aliyuncs.com
|
|||||||
yexuejc.alibaba.oss.access-key-secret=
|
yexuejc.alibaba.oss.access-key-secret=
|
||||||
yexuejc.alibaba.oss.access-key-id=
|
yexuejc.alibaba.oss.access-key-id=
|
||||||
yexuejc.alibaba.oss.bucket=guansichou
|
yexuejc.alibaba.oss.bucket=guansichou
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#========================================================================================================================
|
||||||
|
# security相关
|
||||||
|
#reids
|
||||||
|
#开启指定redis库db0默认开启
|
||||||
|
yexuejc.redis.db1=true
|
||||||
|
spring.redis.jedis.pool.max-active=100
|
||||||
|
spring.redis.jedis.pool.max-idle=10
|
||||||
|
spring.redis.jedis.pool.min-idle=3
|
||||||
|
spring.redis.host=121.42.165.89
|
||||||
|
spring.redis.password=
|
||||||
|
spring.redis.port=16379
|
||||||
|
|
||||||
|
|
||||||
|
#db
|
||||||
|
|
||||||
|
spring.h2.console.path=/h2-console
|
||||||
|
spring.h2.console.enabled=true
|
||||||
|
spring.h2.console.settings.web-allow-others=true
|
||||||
|
spring.datasource.username=sa
|
||||||
|
spring.datasource.password=123456
|
||||||
|
spring.datasource.url=jdbc:h2:mem:test;MODE=PostgreSQL
|
||||||
|
spring.datasource.driver-class-name=org.h2.Driver
|
||||||
|
spring.datasource.schema=classpath:db/schema.sql
|
||||||
|
spring.datasource.data=classpath:db/data.sql
|
||||||
|
|
||||||
|
#========================================================================================================================
|
||||||
|
#mybatis-plus
|
||||||
|
mybatis-plus.mapper-locations=classpath*:mapper/*.xml
|
||||||
|
#实体扫描,多个package用逗号或者分号分隔
|
||||||
|
mybatis-plus.type-aliases-package=com.yexuejc.springboot.base.security.domain
|
||||||
|
#主键类型0:"数据库ID自增", 1:"用户输入ID",2:"该类型为未设置主键类型", 3:"全局唯一ID UUID",4:全局唯一ID (UUID),5:字符串全局唯一ID (idWorker 的字符串表示);
|
||||||
|
mybatis-plus.global-config.db-config.id-type=uuid
|
||||||
|
mybatis-plus.global-config.db-config.db-type=POSTGRE_SQL
|
||||||
|
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
|
||||||
|
mybatis-plus.global-config.db-config.field-strategy=not_empty
|
||||||
|
#驼峰下划线转换
|
||||||
|
mybatis-plus.global-config.db-config.column-underline=true
|
||||||
|
#逻辑删除配置(下面3个配置)
|
||||||
|
mybatis-plus.global-config.db-config.logic-delete-value=true
|
||||||
|
mybatis-plus.global-config.db-config.logic-not-delete-value=false
|
||||||
|
#配置返回数据库(column下划线命名&&返回java实体是驼峰命名),自动匹配无需as(没开启这个,SQL需要写as: select user_id as userId)
|
||||||
|
mybatis-plus.configuration.map-underscore-to-camel-case=true
|
||||||
|
mybatis-plus.configuration.cache-enabled=false
|
||||||
|
#========================================================================================================================
|
||||||
|
34
yexuejc-springboot-base/src/test/resources/db/data.sql
Normal file
34
yexuejc-springboot-base/src/test/resources/db/data.sql
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
INSERT INTO consumer (consumer_id,
|
||||||
|
mobile,
|
||||||
|
pwd,
|
||||||
|
is_enable,
|
||||||
|
is_non_expire,
|
||||||
|
is_non_lock,
|
||||||
|
wechat_id,
|
||||||
|
qq_id,
|
||||||
|
weibo_id,
|
||||||
|
nickname,
|
||||||
|
head,
|
||||||
|
email,
|
||||||
|
sex,
|
||||||
|
roles,
|
||||||
|
pay_pwd,
|
||||||
|
reg_type,
|
||||||
|
source_head)
|
||||||
|
VALUES ('119d8c62b8b04154a073b3f6c3d9e14f',
|
||||||
|
'18202837563',
|
||||||
|
'e10adc3949ba59abbe56e057f20f883e',
|
||||||
|
't',
|
||||||
|
't',
|
||||||
|
't',
|
||||||
|
'ogIXq0HrDq3kS6MAHqMI1RUqBrGw',
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
'18202837563',
|
||||||
|
'head/6dc93e2e0809426ca8a9e6ede30b0b50.JPEG',
|
||||||
|
NULL,
|
||||||
|
'男',
|
||||||
|
'[ROLE_CONSUMER, ROLE_LAYER]',
|
||||||
|
NULL,
|
||||||
|
'S',
|
||||||
|
'https://wx.qlogo.cn/mmopen/vi_32/MftzC3yHluDbjZ9c3sYEibUuXNkC3pha8E6pibZO3Wh0Zop0bqHLcltjmrENc4R8Xm6oJECQGibAxZot1v9PR1hsw/132');
|
42
yexuejc-springboot-base/src/test/resources/db/schema.sql
Normal file
42
yexuejc-springboot-base/src/test/resources/db/schema.sql
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
CREATE TABLE consumer (
|
||||||
|
consumer_id varchar(32) NOT NULL DEFAULT NULL::character varying,
|
||||||
|
mobile varchar(50) NOT NULL DEFAULT NULL::character varying,
|
||||||
|
pwd varchar(32) DEFAULT NULL::character varying,
|
||||||
|
is_enable bool DEFAULT true,
|
||||||
|
is_non_expire bool DEFAULT true,
|
||||||
|
is_non_lock bool DEFAULT true,
|
||||||
|
wechat_id varchar(50) DEFAULT NULL::character varying,
|
||||||
|
qq_id varchar(50) DEFAULT NULL::character varying,
|
||||||
|
weibo_id varchar(50) DEFAULT NULL::character varying,
|
||||||
|
nickname varchar(50) DEFAULT NULL::character varying,
|
||||||
|
head varchar(255) DEFAULT NULL::character varying,
|
||||||
|
email varchar(32) DEFAULT NULL::character varying,
|
||||||
|
sex varchar(1) DEFAULT NULL::character varying,
|
||||||
|
roles varchar(255),
|
||||||
|
pay_pwd varchar(32) DEFAULT NULL::character varying,
|
||||||
|
reg_type varchar(10) ,
|
||||||
|
source_head varchar(255)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
COMMENT ON COLUMN consumer.consumer_id IS '用户id';
|
||||||
|
COMMENT ON COLUMN consumer.mobile IS '手机号';
|
||||||
|
COMMENT ON COLUMN consumer.pwd IS '密码:md5';
|
||||||
|
COMMENT ON COLUMN consumer.is_enable IS '账号是否启用';
|
||||||
|
COMMENT ON COLUMN consumer.is_non_expire IS '账号是否没有过期';
|
||||||
|
COMMENT ON COLUMN consumer.is_non_lock IS '账号是否没有被锁定';
|
||||||
|
COMMENT ON COLUMN consumer.wechat_id IS '微信id';
|
||||||
|
COMMENT ON COLUMN consumer.qq_id IS 'qq id';
|
||||||
|
COMMENT ON COLUMN consumer.weibo_id IS '微博id';
|
||||||
|
COMMENT ON COLUMN consumer.nickname IS '昵称';
|
||||||
|
COMMENT ON COLUMN consumer.head IS '用户头像';
|
||||||
|
COMMENT ON COLUMN consumer.email IS '用户邮箱';
|
||||||
|
COMMENT ON COLUMN consumer.sex IS '用户姓别 ''男'',‘女’';
|
||||||
|
COMMENT ON COLUMN consumer.roles IS '角色、权限';
|
||||||
|
COMMENT ON COLUMN consumer.pay_pwd IS '支付密码';
|
||||||
|
COMMENT ON COLUMN consumer.reg_type IS '注册方式';
|
||||||
|
COMMENT ON COLUMN consumer.source_head IS '第三方源头像路径';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Primary Key structure for table consumer
|
||||||
|
-- ----------------------------
|
||||||
|
ALTER TABLE consumer ADD CONSTRAINT consumer_pkey PRIMARY KEY (consumer_id);
|
@ -0,0 +1,82 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.yexuejc.springboot.base.mapper.ConsumerMapper">
|
||||||
|
|
||||||
|
<!-- 通用查询映射结果 -->
|
||||||
|
<resultMap id="BaseResultMap" type="com.yexuejc.springboot.base.security.domain.Consumer">
|
||||||
|
<id column="consumer_id" property="consumerId"/>
|
||||||
|
<result column="mobile" property="mobile"/>
|
||||||
|
<result column="pwd" property="pwd"/>
|
||||||
|
<result column="is_enable" property="enable"/>
|
||||||
|
<result column="is_non_expire" property="nonExpire"/>
|
||||||
|
<result column="is_non_lock" property="nonLock"/>
|
||||||
|
<result column="wechat_id" property="wechatId"/>
|
||||||
|
<result column="qq_id" property="qqId"/>
|
||||||
|
<result column="weibo_id" property="weiboId"/>
|
||||||
|
<result column="nickname" property="nickname"/>
|
||||||
|
<result column="head" property="head"/>
|
||||||
|
<result column="email" property="email"/>
|
||||||
|
<result column="sex" property="sex"/>
|
||||||
|
<result column="roles" property="roles"
|
||||||
|
typeHandler="com.yexuejc.springboot.base.mapper.handler.JsonTypeHandler"/>
|
||||||
|
<result column="pay_pwd" property="payPwd"/>
|
||||||
|
<result column="reg_type" property="regType"/>
|
||||||
|
<result column="source_head" property="sourceHead"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<insert id="insert">
|
||||||
|
INSERT INTO consumer (consumer_id,
|
||||||
|
mobile,
|
||||||
|
pwd,
|
||||||
|
is_enable,
|
||||||
|
is_non_expire,
|
||||||
|
is_non_lock,
|
||||||
|
wechat_id,
|
||||||
|
qq_id,
|
||||||
|
weibo_id,
|
||||||
|
nickname,
|
||||||
|
head,
|
||||||
|
email,
|
||||||
|
sex,
|
||||||
|
roles,
|
||||||
|
pay_pwd,
|
||||||
|
reg_type,
|
||||||
|
source_head)
|
||||||
|
VALUES (#{consumerId},
|
||||||
|
#{mobile},
|
||||||
|
#{pwd},
|
||||||
|
#{enable},
|
||||||
|
#{nonExpire},
|
||||||
|
#{nonLock},
|
||||||
|
#{wechatId},
|
||||||
|
#{qqId},
|
||||||
|
#{weiboId},
|
||||||
|
#{nickname},
|
||||||
|
#{head},
|
||||||
|
#{email},
|
||||||
|
#{sex},
|
||||||
|
#{roles,typeHandler=com.yexuejc.springboot.base.mapper.handler.JsonTypeHandler},
|
||||||
|
#{payPwd},
|
||||||
|
#{regType},
|
||||||
|
#{sourceHead});
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<select id="selectOne" resultMap="BaseResultMap">
|
||||||
|
select * from consumer
|
||||||
|
<where>${ew.sqlSegment}</where>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<update id="updateRoles">
|
||||||
|
update consumer
|
||||||
|
<set>
|
||||||
|
<if test='et.roles!=null'>
|
||||||
|
roles = #{et.roles,typeHandler=com.yexuejc.springboot.base.mapper.handler.JsonTypeHandler},
|
||||||
|
</if>
|
||||||
|
mdfy_time=now(),
|
||||||
|
mdfy_by=#{et.mdfyBy}
|
||||||
|
</set>
|
||||||
|
where
|
||||||
|
consumer_id=#{et.consumerId}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
</mapper>
|
Loading…
x
Reference in New Issue
Block a user