Commit 2d400fbfec959a06cc710019a264fca9ff225b0a

Authored by 黄 x
1 parent b1dc5067

fix: 允许通过手机验证码登录平台

@@ -52,6 +52,7 @@ import org.thingsboard.server.service.security.auth.oauth2.HttpCookieOAuth2Autho @@ -52,6 +52,7 @@ import org.thingsboard.server.service.security.auth.oauth2.HttpCookieOAuth2Autho
52 import org.thingsboard.server.service.security.auth.rest.RestAuthenticationProvider; 52 import org.thingsboard.server.service.security.auth.rest.RestAuthenticationProvider;
53 import org.thingsboard.server.service.security.auth.rest.RestLoginProcessingFilter; 53 import org.thingsboard.server.service.security.auth.rest.RestLoginProcessingFilter;
54 import org.thingsboard.server.service.security.auth.rest.RestPublicLoginProcessingFilter; 54 import org.thingsboard.server.service.security.auth.rest.RestPublicLoginProcessingFilter;
  55 +import org.thingsboard.server.service.security.auth.yunteng.CodeLoginProcessingFilter;
55 56
56 import java.util.ArrayList; 57 import java.util.ArrayList;
57 import java.util.Arrays; 58 import java.util.Arrays;
@@ -70,9 +71,10 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt @@ -70,9 +71,10 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
70 public static final String WEBJARS_ENTRY_POINT = "/webjars/**"; 71 public static final String WEBJARS_ENTRY_POINT = "/webjars/**";
71 public static final String DEVICE_API_ENTRY_POINT = "/api/v1/**"; 72 public static final String DEVICE_API_ENTRY_POINT = "/api/v1/**";
72 public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login"; 73 public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login";
  74 + public static final String CODE_BASED_LOGIN_ENTRY_POINT = "/api/yt/auth/code/login";
73 public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public"; 75 public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public";
74 public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token"; 76 public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token";
75 - protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**", "/api/license/**"}; 77 + protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**", "/api/license/**", "/api/yt/noauth/**"};
76 public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**"; 78 public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**";
77 public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; 79 public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**";
78 80
@@ -125,6 +127,13 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt @@ -125,6 +127,13 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
125 } 127 }
126 128
127 @Bean 129 @Bean
  130 + protected CodeLoginProcessingFilter buildSmsCodeLoginProcessingFilter() throws Exception{
  131 + CodeLoginProcessingFilter filter = new CodeLoginProcessingFilter(CODE_BASED_LOGIN_ENTRY_POINT, successHandler, failureHandler, objectMapper);
  132 + filter.setAuthenticationManager(this.authenticationManager);
  133 + return filter;
  134 + }
  135 +
  136 + @Bean
128 protected RestPublicLoginProcessingFilter buildRestPublicLoginProcessingFilter() throws Exception { 137 protected RestPublicLoginProcessingFilter buildRestPublicLoginProcessingFilter() throws Exception {
129 RestPublicLoginProcessingFilter filter = new RestPublicLoginProcessingFilter(PUBLIC_LOGIN_ENTRY_POINT, successHandler, failureHandler, objectMapper); 138 RestPublicLoginProcessingFilter filter = new RestPublicLoginProcessingFilter(PUBLIC_LOGIN_ENTRY_POINT, successHandler, failureHandler, objectMapper);
130 filter.setAuthenticationManager(this.authenticationManager); 139 filter.setAuthenticationManager(this.authenticationManager);
@@ -133,7 +142,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt @@ -133,7 +142,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
133 142
134 protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception { 143 protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception {
135 List<String> pathsToSkip = new ArrayList<>(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS)); 144 List<String> pathsToSkip = new ArrayList<>(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS));
136 - pathsToSkip.addAll(Arrays.asList(WS_TOKEN_BASED_AUTH_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT, 145 + pathsToSkip.addAll(Arrays.asList(WS_TOKEN_BASED_AUTH_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT,CODE_BASED_LOGIN_ENTRY_POINT,
137 PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, WEBJARS_ENTRY_POINT)); 146 PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, WEBJARS_ENTRY_POINT));
138 SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT); 147 SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT);
139 JwtTokenAuthenticationProcessingFilter filter 148 JwtTokenAuthenticationProcessingFilter filter
@@ -200,6 +209,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt @@ -200,6 +209,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
200 .antMatchers(WEBJARS_ENTRY_POINT).permitAll() // Webjars 209 .antMatchers(WEBJARS_ENTRY_POINT).permitAll() // Webjars
201 .antMatchers(DEVICE_API_ENTRY_POINT).permitAll() // Device HTTP Transport API 210 .antMatchers(DEVICE_API_ENTRY_POINT).permitAll() // Device HTTP Transport API
202 .antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point 211 .antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point
  212 + .antMatchers(CODE_BASED_LOGIN_ENTRY_POINT).permitAll() // SmsCode Login end-point
203 .antMatchers(PUBLIC_LOGIN_ENTRY_POINT).permitAll() // Public login end-point 213 .antMatchers(PUBLIC_LOGIN_ENTRY_POINT).permitAll() // Public login end-point
204 .antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point 214 .antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point
205 .antMatchers(NON_TOKEN_BASED_AUTH_ENTRY_POINTS).permitAll() // static resources, user activation and password reset end-points 215 .antMatchers(NON_TOKEN_BASED_AUTH_ENTRY_POINTS).permitAll() // static resources, user activation and password reset end-points
@@ -211,6 +221,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt @@ -211,6 +221,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
211 .exceptionHandling().accessDeniedHandler(restAccessDeniedHandler) 221 .exceptionHandling().accessDeniedHandler(restAccessDeniedHandler)
212 .and() 222 .and()
213 .addFilterBefore(buildRestLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class) 223 .addFilterBefore(buildRestLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
  224 + .addFilterBefore(buildSmsCodeLoginProcessingFilter(),UsernamePasswordAuthenticationFilter.class)
214 .addFilterBefore(buildRestPublicLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class) 225 .addFilterBefore(buildRestPublicLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
215 .addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class) 226 .addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
216 .addFilterBefore(buildRefreshTokenProcessingFilter(), UsernamePasswordAuthenticationFilter.class) 227 .addFilterBefore(buildRefreshTokenProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
  1 +package org.thingsboard.server.service.security.auth.yunteng;
  2 +
  3 +import com.fasterxml.jackson.databind.ObjectMapper;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.apache.commons.lang3.StringUtils;
  6 +import org.springframework.http.HttpMethod;
  7 +import org.springframework.security.authentication.AuthenticationServiceException;
  8 +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  9 +import org.springframework.security.core.Authentication;
  10 +import org.springframework.security.core.AuthenticationException;
  11 +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
  12 +import org.springframework.security.web.authentication.AuthenticationFailureHandler;
  13 +import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
  14 +import org.thingsboard.server.common.data.yunteng.dto.request.CodeLoginRequest;
  15 +import org.thingsboard.server.service.security.exception.AuthMethodNotSupportedException;
  16 +import org.thingsboard.server.service.security.model.UserPrincipal;
  17 +
  18 +import javax.servlet.FilterChain;
  19 +import javax.servlet.ServletException;
  20 +import javax.servlet.http.HttpServletRequest;
  21 +import javax.servlet.http.HttpServletResponse;
  22 +import java.io.IOException;
  23 +
  24 +@Slf4j
  25 +public class CodeLoginProcessingFilter extends AbstractAuthenticationProcessingFilter {
  26 +
  27 + private final AuthenticationSuccessHandler successHandler;
  28 + private final AuthenticationFailureHandler failureHandler;
  29 + private final ObjectMapper objectMapper;
  30 +
  31 + public CodeLoginProcessingFilter(
  32 + String defaultProcessUrl,
  33 + AuthenticationSuccessHandler successHandler,
  34 + AuthenticationFailureHandler failureHandler,
  35 + ObjectMapper mapper) {
  36 + super(defaultProcessUrl);
  37 + this.successHandler = successHandler;
  38 + this.failureHandler = failureHandler;
  39 + this.objectMapper = mapper;
  40 + }
  41 +
  42 + @Override
  43 + public Authentication attemptAuthentication(
  44 + HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
  45 + if (!HttpMethod.POST.name().equals(request.getMethod())) {
  46 + if (log.isDebugEnabled()) {
  47 + log.debug("Authentication method not supported. Request method: " + request.getMethod());
  48 + }
  49 + throw new AuthMethodNotSupportedException("Authentication method not supported");
  50 + }
  51 + CodeLoginRequest loginRequest;
  52 + try {
  53 + loginRequest = objectMapper.readValue(request.getReader(), CodeLoginRequest.class);
  54 + } catch (Exception e) {
  55 + throw new AuthenticationServiceException("Invalid login request payload");
  56 + }
  57 + if (StringUtils.isBlank(loginRequest.getCode())
  58 + || StringUtils.isBlank(loginRequest.getPhoneNumber())) {
  59 + throw new AuthenticationServiceException("phone number or sms code not provided");
  60 + }
  61 + UserPrincipal principal =
  62 + new UserPrincipal(UserPrincipal.Type.SMS_CODE, loginRequest.getPhoneNumber());
  63 + UsernamePasswordAuthenticationToken token =
  64 + new UsernamePasswordAuthenticationToken(principal, loginRequest.getCode());
  65 + token.setDetails(authenticationDetailsSource.buildDetails(request));
  66 + return this.getAuthenticationManager().authenticate(token);
  67 + }
  68 +
  69 + @Override
  70 + protected void successfulAuthentication(
  71 + HttpServletRequest request,
  72 + HttpServletResponse response,
  73 + FilterChain chain,
  74 + Authentication authResult)
  75 + throws IOException, ServletException {
  76 + successHandler.onAuthenticationSuccess(request, response, chain, authResult);
  77 + }
  78 +
  79 + @Override
  80 + protected void unsuccessfulAuthentication(
  81 + HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
  82 + throws IOException, ServletException {
  83 + failureHandler.onAuthenticationFailure(request, response, failed);
  84 + }
  85 +}
@@ -423,6 +423,15 @@ caffeine: @@ -423,6 +423,15 @@ caffeine:
423 edges: 423 edges:
424 timeToLiveInMinutes: 1440 424 timeToLiveInMinutes: 1440
425 maxSize: 10000 425 maxSize: 10000
  426 + yunTengIotCache:
  427 + timeToLiveInMinutes: 1440
  428 + maxSize: 10000
  429 + userPermissionFor:
  430 + timeToLiveInMinutes: 1440
  431 + maxSize: 10000
  432 + mobileLoginSmsCode:
  433 + timeToLiveInMinutes: 2
  434 + maxSize: 10000
426 435
427 redis: 436 redis:
428 # standalone or cluster 437 # standalone or cluster
@@ -25,7 +25,9 @@ public interface FastIotConstants { @@ -25,7 +25,9 @@ public interface FastIotConstants {
25 class ConfigJSONKey { 25 class ConfigJSONKey {
26 public static final String BASE_URL = "baseUrl"; 26 public static final String BASE_URL = "baseUrl";
27 } 27 }
28 - 28 + class Relation {
  29 + public static final String relationType = "Created";
  30 + }
29 String DEFAULT_DELIMITER = "#"; 31 String DEFAULT_DELIMITER = "#";
30 32
31 class StateValue { 33 class StateValue {
@@ -56,10 +58,9 @@ public interface FastIotConstants { @@ -56,10 +58,9 @@ public interface FastIotConstants {
56 } 58 }
57 59
58 interface CacheConfigKey { 60 interface CacheConfigKey {
59 - String CACHE_CONFIG_KEY = "YUN_TENG_IOT_CACHE";  
60 - String USER_PERMISSION_PREFIX = "user_permission_for_";  
61 - String MOBILE_LOGIN_SMS_CODE = "mobile_login_sms_code";  
62 - String DEFAULT_RULE_CHAIN = "default_rule_chain"; 61 + String CACHE_CONFIG_KEY = "yunTengIotCache";
  62 + String USER_PERMISSION_PREFIX = "userPermissionFor_";
  63 + String MOBILE_LOGIN_SMS_CODE = "mobileLoginSmsCode";
63 } 64 }
64 65
65 String DEFAULT_EMAIL_SUFFIX_FOR_TB ="@yunteng.com"; 66 String DEFAULT_EMAIL_SUFFIX_FOR_TB ="@yunteng.com";