Browse Source

登陆模块重构

chenweida 7 years ago
parent
commit
405146a525
29 changed files with 820 additions and 140 deletions
  1. 8 0
      base/common-security/pom.xml
  2. 12 1
      base/common-security/readme.MD
  3. 9 1
      base/common-security/src/main/java/com.yihu.base.security/SercurityConfig.java
  4. 4 3
      base/common-security/src/main/java/com.yihu.base.security/config/AuthorizationServerConfig.java
  5. 10 1
      base/common-security/src/main/java/com.yihu.base.security/config/ResourceServerConfig.java
  6. 20 22
      base/common-security/src/main/java/com.yihu.base.security/hander/BseAuthenctiationFailureHandler.java
  7. 15 12
      base/common-security/src/main/java/com.yihu.base.security/properties/AccessTokenPorperties.java
  8. 10 4
      base/common-security/src/main/java/com.yihu.base.security/properties/SecurityProperties.java
  9. 34 0
      base/common-security/src/main/java/com.yihu.base.security/properties/SmsValidateProperties.java
  10. 92 89
      base/common-security/src/main/java/com.yihu.base.security/sms/SmsCodeAuthenticationFilter.java
  11. 1 2
      base/common-security/src/main/java/com.yihu.base.security/sms/SmsCodeAuthenticationProvider.java
  12. 49 0
      base/common-security/src/main/java/com.yihu.base.security/sms/SmsCodeAuthenticationSecurityConfig.java
  13. 2 2
      base/common-security/src/main/java/com.yihu.base.security/sms/SmsCodeAuthenticationToken.java
  14. 40 0
      base/common-security/src/main/java/com.yihu.base.security/sms/controller/SmsController.java
  15. 23 0
      base/common-security/src/main/java/com.yihu.base.security/sms/exception/ValidateCodeException.java
  16. 71 0
      base/common-security/src/main/java/com.yihu.base.security/sms/filter/SmsvalidateCodeFilter.java
  17. 41 0
      base/common-security/src/main/java/com.yihu.base.security/sms/generator/SmsValidateCodeGenerator.java
  18. 17 0
      base/common-security/src/main/java/com.yihu.base.security/sms/generator/ValidateCodeGenerator.java
  19. 160 0
      base/common-security/src/main/java/com.yihu.base.security/sms/process/SmsValidateCodeProcessor.java
  20. 32 0
      base/common-security/src/main/java/com.yihu.base.security/sms/process/ValidateCodeProcessor.java
  21. 25 0
      base/common-security/src/main/java/com.yihu.base.security/sms/sender/DefaultSmsCodeSender.java
  22. 14 0
      base/common-security/src/main/java/com.yihu.base.security/sms/sender/SmsCodeSender.java
  23. 62 0
      base/common-security/src/main/java/com.yihu.base.security/sms/vo/ValidateCode.java
  24. 25 0
      base/common-security/src/main/java/com.yihu.base.security/vo/SimpleResponse.java
  25. 7 2
      base/common-security/src/main/resources/template.yml
  26. 5 0
      svr-lib-parent-pom/pom.xml
  27. 13 1
      svr/svr-demo/src/main/java/com/yihu/jw/service/RbasService.java
  28. 11 0
      svr/svr-demo/src/main/java/com/yihu/jw/service/UserService.java
  29. 8 0
      svr/svr-demo/src/main/resources/application.yml

+ 8 - 0
base/common-security/pom.xml

@ -19,6 +19,10 @@
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
@ -56,6 +60,10 @@
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
        </dependency>
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>

+ 12 - 1
base/common-security/readme.MD

@ -85,6 +85,17 @@ body
**自定义手机号短信验证码登陆**
获取短信
GET
http://localhost:8060/code/sms
body
{
    "mobile":"13612345678"
}
POST
http://localhost:8060/authentication/mobile
@ -93,7 +104,7 @@ header:  Basic {appid}:{appsecuri} 加密  例如 Basic Y3dkOmN3ZA==
body
{
    "mobile":"test",
    "sms":"123456"
    "sms":"246053"
}
返回值

+ 9 - 1
base/common-security/src/main/java/com.yihu.base.security/SercurityConfig.java

@ -1,5 +1,7 @@
package com.yihu.base.security;
import com.yihu.base.security.sms.sender.DefaultSmsCodeSender;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@ -9,9 +11,15 @@ import org.springframework.security.crypto.password.PasswordEncoder;
 * Created by chenweida on 2017/12/4.
 */
@Configuration
public class SercurityConfig   {
public class SercurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Bean
    @ConditionalOnMissingBean
    public DefaultSmsCodeSender defaultSmsCodeSender() {
        return new DefaultSmsCodeSender();
    }
}

+ 4 - 3
base/common-security/src/main/java/com.yihu.base.security/config/AuthorizationServerConfig.java

@ -2,6 +2,7 @@ package com.yihu.base.security.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.base.security.properties.AccessTokenPorperties;
import com.yihu.base.security.properties.SecurityProperties;
import com.yihu.base.security.rbas.ClientServiceProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@ -86,8 +87,8 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
    DefaultTokenServices defaultTokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setAccessTokenValiditySeconds(60 * 60 * accessTokenPorperties.getAccessTokenValiditySeconds()); //默认2小时
        defaultTokenServices.setRefreshTokenValiditySeconds(60 * 60 * accessTokenPorperties.getRefreshTokenValiditySeconds());//默认2小时
        defaultTokenServices.setAccessTokenValiditySeconds(60 * 60 * accessTokenPorperties.getAccessTokenValidityHours()); //默认2小时
        defaultTokenServices.setRefreshTokenValiditySeconds(60 * 60 * accessTokenPorperties.getRefreshTokenValidityHours());//默认2小时
        return defaultTokenServices;
    }
@ -95,7 +96,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
    @Primary
    TokenStore tokenStore() {
        RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);
        redisTokenStore.setPrefix("spring:security:oauth2:");
        redisTokenStore.setPrefix(SecurityProperties.prefix_accesstoken);
        return redisTokenStore;
    }
}

+ 10 - 1
base/common-security/src/main/java/com.yihu.base.security/config/ResourceServerConfig.java

@ -1,6 +1,8 @@
package com.yihu.base.security.config;
import com.yihu.base.security.properties.SecurityProperties;
import com.yihu.base.security.sms.SmsCodeAuthenticationSecurityConfig;
import com.yihu.base.security.sms.filter.SmsvalidateCodeFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
@ -13,6 +15,7 @@ import org.springframework.security.oauth2.provider.authentication.OAuth2Authent
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
 * Created by chenweida on 2017/12/4.
@ -29,6 +32,8 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    private OAuth2AuthenticationManager authenticationManager;
    @Autowired
    private TokenStore redisTokenStore;
    @Autowired
    private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;
    @Override
@ -41,12 +46,16 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
                .successHandler(authenticationSuccessHandler)
                .failureHandler(authenticationFailureHandler)
                .and()
                .apply(smsCodeAuthenticationSecurityConfig)  //添加自定义短信登陆
                .and()
                .authorizeRequests()
                .antMatchers(
                        SecurityProperties.formLogin,
                        SecurityProperties.formLoginPage,
                        SecurityProperties.mobileLogin).permitAll()
                        SecurityProperties.mobileLogin,
                        SecurityProperties.mobileSendSms).permitAll()
                .anyRequest().authenticated()
                //.anyRequest().access("@rbasService.hasPerssion(request,authentication)")
                .and()
                .csrf().disable();
    }

+ 20 - 22
base/common-security/src/main/java/com.yihu.base.security/hander/BseAuthenctiationFailureHandler.java

@ -1,12 +1,14 @@
/**
 * 
 *
 */
package com.yihu.base.security.hander;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.base.security.vo.SimpleResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
@ -17,30 +19,26 @@ import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * @author zhailiang
 *
 * @author chenweida
 */
@Component("BseAuthenctiationFailureHandler")
public class BseAuthenctiationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired
	private ObjectMapper objectMapper;
	
	/* (non-Javadoc)
	 * @see org.springframework.security.web.authentication.AuthenticationFailureHandler#onAuthenticationFailure(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.AuthenticationException)
	 */
	@Override
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
										AuthenticationException exception) throws IOException, ServletException {
		
		logger.info("登录失败");
		
		
	}
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private ObjectMapper objectMapper;
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {
        logger.info("登录失败");
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(objectMapper.writeValueAsString(new SimpleResponse(exception.getMessage())));
    }
}

+ 15 - 12
base/common-security/src/main/java/com.yihu.base.security/properties/AccessTokenPorperties.java

@ -1,31 +1,34 @@
package com.yihu.base.security.properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
 * Created by chenweida on 2017/12/5.
 */
@ConfigurationProperties(prefix = "security.oauth2.token")
@Component
public class AccessTokenPorperties {
    @Value("${security.oauth2.token.accessTokenValidityHours}")
    private Integer accessTokenValidityHours = 2; //accesstoken超时时间
    private Integer accessTokenValiditySeconds = 2; //accesstoken超时时间
    @Value("${security.oauth2.token.refreshTokenValidityHours}")
    private Integer refreshTokenValidityHours = 2;//刷新token过期时间
    private Integer refreshTokenValiditySeconds = 2;//刷新token过期时间
    public Integer getAccessTokenValiditySeconds() {
        return accessTokenValiditySeconds;
    public Integer getAccessTokenValidityHours() {
        return accessTokenValidityHours;
    }
    public void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds) {
        this.accessTokenValiditySeconds = accessTokenValiditySeconds;
    public void setAccessTokenValidityHours(Integer accessTokenValidityHours) {
        this.accessTokenValidityHours = accessTokenValidityHours;
    }
    public Integer getRefreshTokenValiditySeconds() {
        return refreshTokenValiditySeconds;
    public Integer getRefreshTokenValidityHours() {
        return refreshTokenValidityHours;
    }
    public void setRefreshTokenValiditySeconds(Integer refreshTokenValiditySeconds) {
        this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
    public void setRefreshTokenValidityHours(Integer refreshTokenValidityHours) {
        this.refreshTokenValidityHours = refreshTokenValidityHours;
    }
}

+ 10 - 4
base/common-security/src/main/java/com.yihu.base.security/properties/SecurityProperties.java

@ -5,11 +5,17 @@ package com.yihu.base.security.properties;
 * 安全框架配置信息
 */
public class SecurityProperties {
    //放在redis中的前缀
    public final static String prefix_accesstoken = "security:oauth2:";  //oauth2 的前缀
    public final static String prefix_sms = "security:oauth2:smsLogin:";  //短信验证码的前缀
    //表单登陆相关信息
    public static String formLogin = "/authentication/form";
    public static String formLoginPage = "/denglu.html";
    public final static String formLogin = "/authentication/form";//账号密码的路径
    public final static String formLoginPage = "/denglu.html";
    //短信登陆相关信息
    public static String mobileLogin = "/authentication/mobile";
    public static String mobileLoginKey = "mobile";
    public final static String mobileLogin = "/authentication/mobile"; //手机号短信登陆的路径
    public final static String mobileLoginAccountKey = "mobile";
    public final static String mobileLoginSmsKey = "sms";
    public final static String mobileSendSms = "/code/sms";     //发送短信接口的路径
}

+ 34 - 0
base/common-security/src/main/java/com.yihu.base.security/properties/SmsValidateProperties.java

@ -0,0 +1,34 @@
package com.yihu.base.security.properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
 * Created by chenweida on 2017/12/5.
 */
@Component
public class SmsValidateProperties {
    @Value("${security.oauth2.sms.expireIn}")
    private Integer expireIn = 1; //短信验证码过期时间
    @Value("${security.oauth2.sms.length}")
    private Integer length = 6; //短信验证码过期时间
    public Integer getExpireIn() {
        return expireIn;
    }
    public void setExpireIn(Integer expireIn) {
        this.expireIn = expireIn;
    }
    public Integer getLength() {
        return length;
    }
    public void setLength(Integer length) {
        this.length = length;
    }
}

+ 92 - 89
base/common-security/src/main/java/com.yihu.base.security/sms/SmsCodeAuthenticationFilter.java

@ -1,5 +1,5 @@
/**
 *
 * 
 */
package com.yihu.base.security.sms;
@ -15,95 +15,98 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 短信登陆过滤器
 * @author chenweida
 * @author zhailiang
 *
 */
public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    // ~ Static fields/initializers
    // =====================================================================================
    private String mobileParameter = SecurityProperties.mobileLoginKey;
    private boolean postOnly = true;
    // ~ Constructors
    // ===================================================================================================
    public SmsCodeAuthenticationFilter() {
        super(new AntPathRequestMatcher(SecurityProperties.mobileLogin, "POST"));
    }
    // ~ Methods
    // ========================================================================================================
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        String mobile = obtainMobile(request);
        if (mobile == null) {
            mobile = "";
        }
        mobile = mobile.trim();
        SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile);
        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
    }
    /**
     * 获取手机号
     */
    protected String obtainMobile(HttpServletRequest request) {
        return request.getParameter(mobileParameter);
    }
    /**
     * 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, SmsCodeAuthenticationToken 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 setMobileParameter(String usernameParameter) {
        Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
        this.mobileParameter = usernameParameter;
    }
    /**
     * 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 getMobileParameter() {
        return mobileParameter;
    }
	// ~ Static fields/initializers
	// =====================================================================================
	private String mobileParameter = SecurityProperties.mobileLoginAccountKey;
	private boolean postOnly = true;
	// ~ Constructors
	// ===================================================================================================
	public SmsCodeAuthenticationFilter() {
		super(new AntPathRequestMatcher(SecurityProperties.mobileLogin, "POST"));
	}
	// ~ Methods
	// ========================================================================================================
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		if (postOnly && !request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
		}
		String mobile = obtainMobile(request);
		if (mobile == null) {
			mobile = "";
		}
		mobile = mobile.trim();
		SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile);
		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
		return this.getAuthenticationManager().authenticate(authRequest);
	}
	/**
	 * 获取手机号
	 */
	protected String obtainMobile(HttpServletRequest request) {
		return request.getParameter(mobileParameter);
	}
	/**
	 * 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, SmsCodeAuthenticationToken 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 setMobileParameter(String usernameParameter) {
		Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
		this.mobileParameter = usernameParameter;
	}
	/**
	 * 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 getMobileParameter() {
		return mobileParameter;
	}
}

+ 1 - 2
base/common-security/src/main/java/com.yihu.base.security/sms/SmsCodeAuthenticationProvider.java

@ -11,8 +11,7 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
/**
 * 短信登陆处理器
 * @author chenweida
 * @author zhailiang
 *
 */
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {

+ 49 - 0
base/common-security/src/main/java/com.yihu.base.security/sms/SmsCodeAuthenticationSecurityConfig.java

@ -0,0 +1,49 @@
/**
 * 
 */
package com.yihu.base.security.sms;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
/**
 * @author zhailiang
 *
 */
@Component
public class SmsCodeAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
	
	@Autowired
	private AuthenticationSuccessHandler authenticationSuccessHandler;
	
	@Autowired
	private AuthenticationFailureHandler authenticationFailureHandler;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Override
	public void configure(HttpSecurity http) throws Exception {
		
		SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter();
		smsCodeAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
		smsCodeAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
		smsCodeAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler);
		
		SmsCodeAuthenticationProvider smsCodeAuthenticationProvider = new SmsCodeAuthenticationProvider();
		smsCodeAuthenticationProvider.setUserDetailsService(userDetailsService);
		
		http.authenticationProvider(smsCodeAuthenticationProvider)
			.addFilterAfter(smsCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
		
	}
}

+ 2 - 2
base/common-security/src/main/java/com.yihu.base.security/sms/SmsCodeAuthenticationToken.java

@ -10,7 +10,7 @@ import org.springframework.security.core.SpringSecurityCoreVersion;
import java.util.Collection;
/**
 * @author chenweida
 * @author zhailiang
 *
 */
public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {
@ -48,7 +48,7 @@ public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {
	 * @param authorities
	 */
	public SmsCodeAuthenticationToken(Object principal,
									  Collection<? extends GrantedAuthority> authorities) {
			Collection<? extends GrantedAuthority> authorities) {
		super(authorities);
		this.principal = principal;
		super.setAuthenticated(true); // must use super, as we override

+ 40 - 0
base/common-security/src/main/java/com.yihu.base.security/sms/controller/SmsController.java

@ -0,0 +1,40 @@
package com.yihu.base.security.sms.controller;
import com.yihu.base.security.properties.SecurityProperties;
import com.yihu.base.security.sms.process.SmsValidateCodeProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Created by chenweida on 2017/12/5.
 */
@RestController
public class SmsController {
    @Autowired
    private SmsValidateCodeProcessor smsValidateCodeProcessor;
    /**
     * 创建验证码
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @GetMapping(SecurityProperties.mobileSendSms)
    public void createCode(
            HttpServletRequest request,
            HttpServletResponse response)
            throws Exception {
        //获取手机号
        String mobile = request.getParameter(SecurityProperties.mobileLoginAccountKey);
        //发送短信验证码并且保存到redis中
        smsValidateCodeProcessor.create(new ServletWebRequest(request, response));
    }
}

+ 23 - 0
base/common-security/src/main/java/com.yihu.base.security/sms/exception/ValidateCodeException.java

@ -0,0 +1,23 @@
/**
 * 
 */
package com.yihu.base.security.sms.exception;
import org.springframework.security.core.AuthenticationException;
/**
 * @author chenweida
 *
 */
public class ValidateCodeException extends AuthenticationException {
	/**
	 * 
	 */
	private static final long serialVersionUID = -7285211528095468156L;
	public ValidateCodeException(String msg) {
		super(msg);
	}
}

+ 71 - 0
base/common-security/src/main/java/com.yihu.base.security/sms/filter/SmsvalidateCodeFilter.java

@ -0,0 +1,71 @@
/**
 *
 */
package com.yihu.base.security.sms.filter;
import com.yihu.base.security.properties.SecurityProperties;
import com.yihu.base.security.sms.exception.ValidateCodeException;
import com.yihu.base.security.sms.process.SmsValidateCodeProcessor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * @author chenweida
 */
@Component("smsvalidateCodeFilter")
public class SmsvalidateCodeFilter extends OncePerRequestFilter implements InitializingBean {
    /**
     * 验证码校验失败处理器
     */
    @Autowired
    private AuthenticationFailureHandler authenticationFailureHandler;
    /**
     * 验证请求url与配置的url是否匹配的工具类
     */
    private AntPathMatcher pathMatcher = new AntPathMatcher();
    @Autowired
    private SmsValidateCodeProcessor smsValidateCodeProcessor;
    /*
     * (non-Javadoc)
     *
     * @see
     * org.springframework.web.filter.OncePerRequestFilter#doFilterInternal(
     * javax.servlet.http.HttpServletRequest,
     * javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        if (!StringUtils.equalsIgnoreCase(request.getMethod(), "get")) {
            if (pathMatcher.match(SecurityProperties.mobileSendSms, request.getRequestURI())) {
                logger.info("校验请求(" + request.getRequestURI() + ")中的验证码");
                try {
                    smsValidateCodeProcessor
                            .validate(new ServletWebRequest(request, response));
                    logger.info("验证码校验通过");
                } catch (ValidateCodeException exception) {
                    authenticationFailureHandler.onAuthenticationFailure(request, response, exception);
                    return;
                }
            }
        }
        chain.doFilter(request, response);
    }
}

+ 41 - 0
base/common-security/src/main/java/com.yihu.base.security/sms/generator/SmsValidateCodeGenerator.java

@ -0,0 +1,41 @@
package com.yihu.base.security.sms.generator;
import com.yihu.base.security.properties.SmsValidateProperties;
import com.yihu.base.security.sms.vo.ValidateCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.ServletWebRequest;
import java.util.Random;
/**
 * Created by chenweida on 2017/12/5.
 * 短信验证码生成器
 */
@Component
public class SmsValidateCodeGenerator implements ValidateCodeGenerator {
    @Autowired
    private SmsValidateProperties smsValidateProperties;
    @Override
    public ValidateCode generate(ServletWebRequest request) {
        String code = getFixLenthString(smsValidateProperties.getLength());
        ValidateCode validateCode = new ValidateCode(code, smsValidateProperties.getExpireIn());
        return validateCode;
    }
    /*
 * 返回长度为【strLength】的随机数,在前面补0
 */
    private String getFixLenthString(int strLength) {
        Random rm = new Random();
        // 获得随机数
        double pross = (1 + rm.nextDouble()) * Math.pow(10, strLength);
        // 将获得的获得随机数转化为字符串
        String fixLenthString = String.valueOf(pross);
        // 返回固定的长度的随机数
        return fixLenthString.substring(1, strLength + 1);
    }
}

+ 17 - 0
base/common-security/src/main/java/com.yihu.base.security/sms/generator/ValidateCodeGenerator.java

@ -0,0 +1,17 @@
/**
 * 
 */
package com.yihu.base.security.sms.generator;
import com.yihu.base.security.sms.vo.ValidateCode;
import org.springframework.web.context.request.ServletWebRequest;
/**
 * @author chenweida
 *
 */
public interface ValidateCodeGenerator {
	ValidateCode generate(ServletWebRequest request);
	
}

+ 160 - 0
base/common-security/src/main/java/com.yihu.base.security/sms/process/SmsValidateCodeProcessor.java

@ -0,0 +1,160 @@
/**
 *
 */
package com.yihu.base.security.sms.process;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.yihu.base.security.properties.SecurityProperties;
import com.yihu.base.security.sms.exception.ValidateCodeException;
import com.yihu.base.security.sms.generator.SmsValidateCodeGenerator;
import com.yihu.base.security.sms.generator.ValidateCodeGenerator;
import com.yihu.base.security.sms.sender.SmsCodeSender;
import com.yihu.base.security.sms.vo.ValidateCode;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;
import java.util.Map;
/**
 * @author chenweida
 */
@Component
public class SmsValidateCodeProcessor implements ValidateCodeProcessor {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SmsCodeSender smsCodeSender;
    @Autowired
    private SmsValidateCodeGenerator smsValidateCodeGenerator;
    /*
     * (non-Javadoc)
     *
     * @see
     * com.imooc.security.core.validate.code.ValidateCodeProcessor#create(org.
     * springframework.web.context.request.ServletWebRequest)
     */
    @Override
    public void create(ServletWebRequest request) throws Exception {
        ValidateCode validateCode = generate(request);
        save(request, validateCode);
        send(request, validateCode);
    }
    /**
     * 生成校验码
     *
     * @param request
     * @return
     */
    @SuppressWarnings("unchecked")
    private ValidateCode generate(ServletWebRequest request) {
        return smsValidateCodeGenerator.generate(request);
    }
    /**
     * 保存校验码
     *
     * @param request
     * @param validateCode
     */
    private void save(ServletWebRequest request, ValidateCode validateCode) {
        JSONObject jo = new JSONObject();
        jo.put("code", validateCode.getCode());
        jo.put("expireTime", validateCode.getExpireTimeString());
        redisTemplate.opsForValue().set(key(request), jo.toString());
    }
    /**
     * 删除严验证码
     *
     * @param request
     */
    private void reomve(ServletWebRequest request) {
        redisTemplate.delete((key(request)));
    }
    /**
     * 获取校验码
     *
     * @param request
     */
    private ValidateCode get(ServletWebRequest request) {
        String joStr = redisTemplate.opsForValue().get(key(request));
        if (StringUtils.isNotBlank(joStr)) {
            JSONObject jo = JSONObject.fromObject(joStr);
            ValidateCode validateCode = new ValidateCode();
            validateCode.setCode(jo.getString("code"));
            validateCode.setExpireTimeString(jo.getString("expireTime"));
            return validateCode;
        } else {
            return null;
        }
    }
    /**
     * 拼凑放在redis的key
     *
     * @param request
     * @return
     */
    private String key(ServletWebRequest request) {
        return SecurityProperties.prefix_sms + request.getParameter(SecurityProperties.mobileLoginAccountKey);
    }
    /**
     * 发送校验码,由子类实现
     *
     * @param request
     * @param validateCode
     * @throws Exception
     */
    protected void send(ServletWebRequest request, ValidateCode validateCode) throws Exception {
        smsCodeSender.send(request.getParameter(SecurityProperties.mobileLoginAccountKey), validateCode.getCode());
    }
    @SuppressWarnings("unchecked")
    @Override
    public void validate(ServletWebRequest request) {
        String sessionKey = key(request);
        //获取验证码
        ValidateCode validateCode = get(request);
        String codeInRequest;
        //获取请求中的验证码
        try {
            codeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(),
                    SecurityProperties.mobileSendSms);
        } catch (ServletRequestBindingException e) {
            throw new ValidateCodeException("获取验证码的值失败");
        }
        if (StringUtils.isBlank(codeInRequest)) {
            throw new ValidateCodeException("验证码的值不能为空");
        }
        if (validateCode == null) {
            throw new ValidateCodeException("验证码不存在");
        }
        if (validateCode.isExpried()) {
            reomve(request);
            throw new ValidateCodeException("验证码已过期");
        }
        if (!StringUtils.equals(validateCode.getCode(), codeInRequest)) {
            throw new ValidateCodeException("验证码不匹配");
        }
        //验证成功删除验证码
        reomve(request);
    }
}

+ 32 - 0
base/common-security/src/main/java/com.yihu.base.security/sms/process/ValidateCodeProcessor.java

@ -0,0 +1,32 @@
/**
 * 
 */
package com.yihu.base.security.sms.process;
import org.springframework.web.context.request.ServletWebRequest;
/**
 * 校验码处理器,封装不同校验码的处理逻辑
 * 
 * @author chenweida
 *
 */
public interface ValidateCodeProcessor {
	/**
	 * 创建校验码
	 * 
	 * @param request
	 * @throws Exception
	 */
	void create(ServletWebRequest request) throws Exception;
	/**
	 * 校验验证码
	 * 
	 * @param servletWebRequest
	 * @throws Exception
	 */
	void validate(ServletWebRequest servletWebRequest);
}

+ 25 - 0
base/common-security/src/main/java/com.yihu.base.security/sms/sender/DefaultSmsCodeSender.java

@ -0,0 +1,25 @@
/**
 *
 */
package com.yihu.base.security.sms.sender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
 * @author chenweida
 *         默认的短信发送 没有具体实现
 */
public class DefaultSmsCodeSender implements SmsCodeSender {
    private Logger logger = LoggerFactory.getLogger(DefaultSmsCodeSender.class);
    /* (non-Javadoc)
     * @see com.imooc.security.core.validate.code.sms.SmsCodeSender#send(java.lang.String, java.lang.String)
     */
    @Override
    public void send(String mobile, String code) {
        logger.info("向手机" + mobile + "发送短信验证码" + code);
    }
}

+ 14 - 0
base/common-security/src/main/java/com.yihu.base.security/sms/sender/SmsCodeSender.java

@ -0,0 +1,14 @@
/**
 * 
 */
package com.yihu.base.security.sms.sender;
/**
 * @author chenweida
 *
 */
public interface SmsCodeSender {
	
	void send(String mobile, String code);
}

+ 62 - 0
base/common-security/src/main/java/com.yihu.base.security/sms/vo/ValidateCode.java

@ -0,0 +1,62 @@
/**
 *
 */
package com.yihu.base.security.sms.vo;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
 * @author chenweida
 */
public class ValidateCode implements Serializable {
    private String code;
    private LocalDateTime expireTime;
    public ValidateCode() {
    }
    public ValidateCode(String code, int expireIn) {
        this.code = code;
        this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
    }
    public ValidateCode(String code, LocalDateTime expireTime) {
        this.code = code;
        this.expireTime = expireTime;
    }
    public boolean isExpried() {
        return LocalDateTime.now().isAfter(expireTime);
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public LocalDateTime getExpireTime() {
        return expireTime;
    }
    public void setExpireTime(LocalDateTime expireTime) {
        this.expireTime = expireTime;
    }
    public String getExpireTimeString() {
        return expireTime.format(DateTimeFormatter.ISO_DATE_TIME);
    }
    public void setExpireTimeString(String strTime) {
        expireTime = LocalDateTime.parse(strTime, DateTimeFormatter.ISO_DATE_TIME);
    }
}

+ 25 - 0
base/common-security/src/main/java/com.yihu.base.security/vo/SimpleResponse.java

@ -0,0 +1,25 @@
/**
 * 
 */
package com.yihu.base.security.vo;
/**
 * chenweida
 */
public class SimpleResponse {
	
	public SimpleResponse(Object content){
		this.content = content;
	}
	
	private Object content;
	public Object getContent() {
		return content;
	}
	public void setContent(Object content) {
		this.content = content;
	}
	
}

+ 7 - 2
base/common-security/src/main/resources/template.yml

@ -28,8 +28,13 @@ spring:
  aop:
    proxy-target-class: true
security:
  oauth2:
    token:
      accessTokenValiditySeconds: 2 # 2小时
      refreshTokenValiditySeconds: 2 # 2小时
      accessTokenValidityHours: 2 # 2小时
      refreshTokenValidityHours: 2 # 2小时
    sms:
      expireIn: 1 ##1分钟
      length: 6 #验证码长度

+ 5 - 0
svr-lib-parent-pom/pom.xml

@ -322,6 +322,11 @@
                <artifactId>spring-boot-starter-jdbc</artifactId>
                <version>${version.springBoot}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <version>${version.springBoot}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>

+ 13 - 1
svr/svr-demo/src/main/java/com/yihu/jw/service/RbasService.java

@ -1,7 +1,19 @@
package com.yihu.jw.service;
import com.yihu.base.security.rbas.IRbasService;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
/**
 * Created by chenweida on 2017/12/5.
 * 判断用户是否有权限访问该路径
 */
public class RbasService {
@Service("rbasService")
public class RbasService implements IRbasService {
    @Override
    public Boolean hasPerssion(HttpServletRequest request, Authentication authentication) {
        return true;
    }
}

+ 11 - 0
svr/svr-demo/src/main/java/com/yihu/jw/service/UserService.java

@ -15,6 +15,7 @@ import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
@ -50,6 +51,16 @@ public class UserService implements UserDetailsService {
                    true
                    , AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_USER") //权限
            );
        } else if ((!StringUtils.isEmpty(userName))&&userName.length() == 11) {
            System.out.printf("password:" + passwordEncoder.encode("123456"));
            return new User("admin",
                    passwordEncoder.encode("123456"),
                    true,
                    true,
                    true,
                    true
                    , AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_USER") //权限
            );
        } else {
            throw new UsernameNotFoundException("用户不存在");
        }

+ 8 - 0
svr/svr-demo/src/main/resources/application.yml

@ -41,3 +41,11 @@ quartz:
  overwriteExistingJobs: true ##是否覆盖job
security:
  oauth2:
    token:
      accessTokenValidityHours: 2 # 2小时
      refreshTokenValidityHours: 2 # 2小时
    sms:
      expireIn: 1 ##1分钟
      length: 6 #验证码长度