Commit 2d400fbfec959a06cc710019a264fca9ff225b0a

Authored by 黄 x
1 parent b1dc5067

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

... ... @@ -52,6 +52,7 @@ import org.thingsboard.server.service.security.auth.oauth2.HttpCookieOAuth2Autho
52 52 import org.thingsboard.server.service.security.auth.rest.RestAuthenticationProvider;
53 53 import org.thingsboard.server.service.security.auth.rest.RestLoginProcessingFilter;
54 54 import org.thingsboard.server.service.security.auth.rest.RestPublicLoginProcessingFilter;
  55 +import org.thingsboard.server.service.security.auth.yunteng.CodeLoginProcessingFilter;
55 56
56 57 import java.util.ArrayList;
57 58 import java.util.Arrays;
... ... @@ -70,9 +71,10 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
70 71 public static final String WEBJARS_ENTRY_POINT = "/webjars/**";
71 72 public static final String DEVICE_API_ENTRY_POINT = "/api/v1/**";
72 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 75 public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public";
74 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 78 public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**";
77 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 127 }
126 128
127 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 137 protected RestPublicLoginProcessingFilter buildRestPublicLoginProcessingFilter() throws Exception {
129 138 RestPublicLoginProcessingFilter filter = new RestPublicLoginProcessingFilter(PUBLIC_LOGIN_ENTRY_POINT, successHandler, failureHandler, objectMapper);
130 139 filter.setAuthenticationManager(this.authenticationManager);
... ... @@ -133,7 +142,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
133 142
134 143 protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception {
135 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 146 PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, WEBJARS_ENTRY_POINT));
138 147 SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT);
139 148 JwtTokenAuthenticationProcessingFilter filter
... ... @@ -200,6 +209,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
200 209 .antMatchers(WEBJARS_ENTRY_POINT).permitAll() // Webjars
201 210 .antMatchers(DEVICE_API_ENTRY_POINT).permitAll() // Device HTTP Transport API
202 211 .antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point
  212 + .antMatchers(CODE_BASED_LOGIN_ENTRY_POINT).permitAll() // SmsCode Login end-point
203 213 .antMatchers(PUBLIC_LOGIN_ENTRY_POINT).permitAll() // Public login end-point
204 214 .antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point
205 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 221 .exceptionHandling().accessDeniedHandler(restAccessDeniedHandler)
212 222 .and()
213 223 .addFilterBefore(buildRestLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
  224 + .addFilterBefore(buildSmsCodeLoginProcessingFilter(),UsernamePasswordAuthenticationFilter.class)
214 225 .addFilterBefore(buildRestPublicLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
215 226 .addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
216 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 423 edges:
424 424 timeToLiveInMinutes: 1440
425 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 436 redis:
428 437 # standalone or cluster
... ...
... ... @@ -25,7 +25,9 @@ public interface FastIotConstants {
25 25 class ConfigJSONKey {
26 26 public static final String BASE_URL = "baseUrl";
27 27 }
28   -
  28 + class Relation {
  29 + public static final String relationType = "Created";
  30 + }
29 31 String DEFAULT_DELIMITER = "#";
30 32
31 33 class StateValue {
... ... @@ -56,10 +58,9 @@ public interface FastIotConstants {
56 58 }
57 59
58 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 66 String DEFAULT_EMAIL_SUFFIX_FOR_TB ="@yunteng.com";
... ...