您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“springsecurity如何實現基于token的認證方式”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“springsecurity如何實現基于token的認證方式”這篇文章吧。
在簡析了spring security oauth的源碼之后,我們發現,其實有些源碼我們并不能用,至少,TokenEndPoint這個組件,我們就沒法用,因為這個組件只會響應/oauth/token
的請求,而且spring security oauth會根據OAuth協議中常用的4種授權模式去生成令牌,而我們這里是自定義的登錄,自然用不上OAuth協議中的授權模式,因此我們改造自定義的登錄,只能借鑒其令牌生成方式。
如果有印象,在前幾篇博客中總結過自定義登錄成功處理的方式,無論前面登錄邏輯如何認證,我們只需要在認證成功之后,自定義生成AccessToken 即可,因此我們只需要重新處理我們自定義登錄成功的處理方式即可。
那么如何處理,依舊是一個問題,這就回到了上一篇博客中的內容,構造AccessToken需要OAuth3Request和Authentication,其中Authentication是登錄成功后的認證詳情信息,在登錄成功處理器中,會有相關參數傳遞進來。OAuth3Request由ClientDeatails和TokenRequest組成,這在上一篇博客中我們已經總結過了,ClientDetails根據傳遞參數中的ClientId和clientSecret等client配置信息組成,TokenRequest則由請求中其他參數實例化而成,具體如下圖所示
相關改造代碼如下
/** * autor:liman * createtime:2021/7/10 * comment: 自定義登錄成功處理器 */ @Component("selfAuthenticationSuccessHandler") @Slf4j public class SelfAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { @Autowired private SecurityProperties securityProperties; @Autowired private ObjectMapper objectMapper; @Autowired private ClientDetailsService clientDetailsService; @Autowired private AuthorizationServerTokenServices authenticationServerTokenServices; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response , Authentication authentication) throws IOException, ServletException { log.info("自定義登錄成功的處理器"); String header = request.getHeader("Authorization"); if (header == null || !header.startsWith("Basic ")) { throw new UnapprovedClientAuthenticationException("請求頭中沒有client相關的信息"); } String[] tokens = extractAndDecodeHeader(header, request); assert tokens.length == 2; String clientId = tokens[0]; String clientSecret = tokens[1]; //得到clientDeatils信息 ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);//得到clientDetails信息 if (null == clientDetails) { throw new UnapprovedClientAuthenticationException("clientid對應的信息不存在" + clientId); } else if (!StringUtils.equals(clientSecret, clientDetails.getClientSecret())) { throw new UnapprovedClientAuthenticationException("clientSecret信息不匹配" + clientSecret); } //構建自己的tokenRequest,由于這里不能使用OAuth3中的四種授權模式,因此這里第四個參數設置為"customer" //同理,第一個參數主要用于組裝并生成Authentication,而這里的Authentication已經通過參數傳遞進來,因此可以直接賦一個空的Map TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP, clientId, clientDetails.getScope(), "customer"); //構建OAuth3Request OAuth3Request oAuth3Request = tokenRequest.createOAuth3Request(clientDetails); //構建 OAuth3Authentication OAuth3Authentication oAuth3Authentication = new OAuth3Authentication(oAuth3Request, authentication); //生成accessToken,這里依舊使用的是spring security oauth中默認的DefaultTokenService OAuth3AccessToken accessToken = authenticationServerTokenServices.createAccessToken(oAuth3Authentication); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(objectMapper.writeValueAsString(accessToken));//將authentication作為json寫到前端 } /** * Decodes the header into a username and password. * * @throws BadCredentialsException if the Basic header is not present or is not valid * Base64 */ //TODO:解碼請求頭中的Base64編碼的 appId和AppSecret private String[] extractAndDecodeHeader(String header, HttpServletRequest request) throws IOException { //格式:Basic+空格+Base64加密的appid和AppSecret,所以這里substring(6) byte[] base64Token = header.substring(6).getBytes("UTF-8"); byte[] decoded; try { decoded = Base64.decode(base64Token); } catch (IllegalArgumentException e) { throw new BadCredentialsException( "Failed to decode basic authentication token"); } String token = new String(decoded, "UTF-8"); int delim = token.indexOf(":"); if (delim == -1) { throw new BadCredentialsException("Invalid basic authentication token"); } return new String[]{token.substring(0, delim), token.substring(delim + 1)}; } }
之前提到過,由于基于token的認證交互,其實不一定會有session會話的概念,如果我們的驗證碼依舊存于session中,則并不能正常校驗,因此在基于token的短信驗證碼登錄的重構中,我們唯一要做的,就是將驗證碼存于Redis等緩存中間件中,驗證碼的key值為deviceid。
方案比較簡單,這里只貼出Redis操作驗證碼的方法
/** * 基于redis的驗證碼存取器,避免由于沒有session導致無法存取驗證碼的問題 */ @Component public class RedisValidateCodeRepository implements ValidateCodeRepository { @Autowired private RedisTemplate<Object, Object> redisTemplate; /* * (non-Javadoc) */ @Override public void save(ServletWebRequest request, ValidateCode code, ValidateCodeType type) { redisTemplate.opsForValue().set(buildKey(request, type), code, 30, TimeUnit.MINUTES); } /* * (non-Javadoc) */ @Override public ValidateCode get(ServletWebRequest request, ValidateCodeType type) { Object value = redisTemplate.opsForValue().get(buildKey(request, type)); if (value == null) { return null; } return (ValidateCode) value; } /* * (non-Javadoc) * */ @Override public void remove(ServletWebRequest request, ValidateCodeType type) { redisTemplate.delete(buildKey(request, type)); } /** * @param request * @param type * @return */ private String buildKey(ServletWebRequest request, ValidateCodeType type) { String deviceId = request.getHeader("deviceId"); if (StringUtils.isBlank(deviceId)) { throw new ValidateCodeException("請在請求頭中攜帶deviceId參數"); } return "code:" + type.toString().toLowerCase() + ":" + deviceId; } }
在調通微信社交登錄之后,再進行總結,只是需要明確的是,這里分為兩種情況,一種是簡化模式,一種是標準的OAuth3授權模式(這兩種的區別,在QQ登錄和微信登錄流程中有詳細的體現)。
簡化的OAuth模式,OAuth協議簡化的認證模式,與標準最大的不同,其實就是在獲取授權碼的時候,順帶將openId(第三方用戶id)和accessToken(獲取用戶信息的令牌),在這種前后端徹底分離的架構中,前三步前端可以通過服務提供商的SDK完成openId和AccessToken的獲取。但是并不能根據openId作為我們自己登錄系統憑證,因此我們需要提供一個根據openId進行登錄的方式這個與之前短信登錄方式大同小異
1、OpenIdAuthenticationToken
/** * autor:liman * createtime:2021/8/4 * comment:OpenIdAuthenticationToken */ public class OpenIdAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final Object principal; private String providerId; /** openId,和providerId作為principal */ public OpenIdAuthenticationToken(String openId, String providerId) { super(null); this.principal = openId; this.providerId = providerId; setAuthenticated(false); } /** * This constructor should only be used by <code>AuthenticationManager</code> or * <code>AuthenticationProvider</code> implementations that are satisfied with * producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>) * authentication token. * * @param principal * @param credentials * @param authorities */ public OpenIdAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) { super(authorities); this.principal = principal; super.setAuthenticated(true); // must use super, as we override } public Object getCredentials() { return null; } public Object getPrincipal() { return this.principal; } public String getProviderId() { return providerId; } public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { if (isAuthenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public void eraseCredentials() { super.eraseCredentials(); } }
2、OpenIdAuthenticationFilter
/** * autor:liman * createtime:2021/8/4 * comment:基于openId登錄的過濾器 */ @Slf4j public class OpenIdAuthenticationFilter extends AbstractAuthenticationProcessingFilter { private String openIdParameter = "openId"; private String providerIdParameter = "providerId"; private boolean postOnly = true; public OpenIdAuthenticationFilter() { super(new AntPathRequestMatcher("/authentication/openid", "POST")); } public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } //獲取請求中的openId和providerId String openid = obtainOpenId(request); String providerId = obtainProviderId(request); if (openid == null) { openid = ""; } if (providerId == null) { providerId = ""; } openid = openid.trim(); providerId = providerId.trim(); //構造OpenIdAuthenticationToken OpenIdAuthenticationToken authRequest = new OpenIdAuthenticationToken(openid, providerId); // Allow subclasses to set the "details" property setDetails(request, authRequest); //交給AuthenticationManager進行認證 return this.getAuthenticationManager().authenticate(authRequest); } /** * 獲取openId */ protected String obtainOpenId(HttpServletRequest request) { return request.getParameter(openIdParameter); } /** * 獲取提供商id */ protected String obtainProviderId(HttpServletRequest request) { return request.getParameter(providerIdParameter); } protected void setDetails(HttpServletRequest request, OpenIdAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } public void setOpenIdParameter(String openIdParameter) { Assert.hasText(openIdParameter, "Username parameter must not be empty or null"); this.openIdParameter = openIdParameter; } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } public final String getOpenIdParameter() { return openIdParameter; } public String getProviderIdParameter() { return providerIdParameter; } public void setProviderIdParameter(String providerIdParameter) { this.providerIdParameter = providerIdParameter; } }
3、OpenIdAuthenticationProvider
/** * */ package com.learn.springsecurity.app.social.openid; /** * @author zhailiang * */ public class OpenIdAuthenticationProvider implements AuthenticationProvider { private SocialUserDetailsService userDetailsService; private UsersConnectionRepository usersConnectionRepository; /* * (non-Javadoc) * * @see org.springframework.security.authentication.AuthenticationProvider# * authenticate(org.springframework.security.core.Authentication) */ @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { OpenIdAuthenticationToken authenticationToken = (OpenIdAuthenticationToken) authentication; Set<String> providerUserIds = new HashSet<>(); providerUserIds.add((String) authenticationToken.getPrincipal()); //之前社交登錄中介紹的usersConnectionRepository,從user_connection表中根據providerId和openId查詢用戶id Set<String> userIds = usersConnectionRepository.findUserIdsConnectedTo(authenticationToken.getProviderId(), providerUserIds); if(CollectionUtils.isEmpty(userIds) || userIds.size() != 1) { throw new InternalAuthenticationServiceException("無法獲取用戶信息"); } //獲取到userId了 String userId = userIds.iterator().next(); //利用UserDetailsService根據userId查詢用戶信息 UserDetails user = userDetailsService.loadUserByUserId(userId); if (user == null) { throw new InternalAuthenticationServiceException("無法獲取用戶信息"); } OpenIdAuthenticationToken authenticationResult = new OpenIdAuthenticationToken(user, user.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } /* * (non-Javadoc) * * @see org.springframework.security.authentication.AuthenticationProvider# * supports(java.lang.Class) */ @Override public boolean supports(Class<?> authentication) { return OpenIdAuthenticationToken.class.isAssignableFrom(authentication); } public SocialUserDetailsService getUserDetailsService() { return userDetailsService; } public void setUserDetailsService(SocialUserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } public UsersConnectionRepository getUsersConnectionRepository() { return usersConnectionRepository; } public void setUsersConnectionRepository(UsersConnectionRepository usersConnectionRepository) { this.usersConnectionRepository = usersConnectionRepository; } }
4、配置類
/** * @author zhailiang * */ @Component public class OpenIdAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { @Autowired private AuthenticationSuccessHandler selfAuthenticationSuccessHandler; @Autowired private AuthenticationFailureHandler selfAuthenticationFailureHandler; @Autowired private SocialUserDetailsService userDetailsService; @Autowired private UsersConnectionRepository usersConnectionRepository; @Override public void configure(HttpSecurity http) throws Exception { OpenIdAuthenticationFilter OpenIdAuthenticationFilter = new OpenIdAuthenticationFilter(); OpenIdAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); OpenIdAuthenticationFilter.setAuthenticationSuccessHandler(selfAuthenticationSuccessHandler); OpenIdAuthenticationFilter.setAuthenticationFailureHandler(selfAuthenticationFailureHandler); OpenIdAuthenticationProvider OpenIdAuthenticationProvider = new OpenIdAuthenticationProvider(); OpenIdAuthenticationProvider.setUserDetailsService(userDetailsService); OpenIdAuthenticationProvider.setUsersConnectionRepository(usersConnectionRepository); http.authenticationProvider(OpenIdAuthenticationProvider) .addFilterAfter(OpenIdAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } }
測試結果
標準的OAuth模式
針對標準的授權模式,我們并不需要做多少改動,因為在社交登錄那一節中我們已經做了相關開發,只是需要說明的是,只是在spring-social的過濾器——SocialAuthenticationFilter
中,在正常社交登錄流程完成之后會默認跳轉到某個頁面,而這個并不適用于前后端分離的項目,因此要針對這個問題定制化解決。這需要回到之前SocialAuthenticationFilter
加入到認證過濾器鏈上的代碼。之前我們說過社交登錄的過濾器鏈不需要我們手動配置,只需要初始化SpringSocialConfiguer的時候,會自動加入到社交登錄的認證過濾器鏈上
@Configuration @EnableSocial public class SocialConfig extends SocialConfigurerAdapter { @Bean public SpringSocialConfigurer selfSocialSecurityConfig(){ SpringSocialConfigurer selfSpringSocialConfig = new SpringSocialConfigurer(); return selfSpringSocialConfig; } }
我們只需要改變SocialAuthenticationFilter
的默認處理即可,因此我們給他加一個后置處理器,但是這個后置處理器是在SpringSocialConfigurer的postProcess函數中進行處理
/** * autor:liman * createtime:2021/7/15 * comment:自定義的springsocial配置類 */ public class SelfSpringSocialConfig extends SpringSocialConfigurer { private String processFilterUrl; @Autowired(required = false) private ConnectionSignUp connectionSignUp; @Autowired(required = false) private SocialAuthenticationFilterPostProcessor socialAuthenticationFilterPostProcessor; public SelfSpringSocialConfig(String processFilterUrl) { this.processFilterUrl = processFilterUrl; } @Override protected <T> T postProcess(T object) { SocialAuthenticationFilter socialAuthenticationFilter = (SocialAuthenticationFilter) super.postProcess(object); socialAuthenticationFilter.setFilterProcessesUrl(processFilterUrl); if(null!=socialAuthenticationFilterPostProcessor){ socialAuthenticationFilterPostProcessor.process(socialAuthenticationFilter); } return (T) socialAuthenticationFilter; } public ConnectionSignUp getConnectionSignUp() { return connectionSignUp; } public void setConnectionSignUp(ConnectionSignUp connectionSignUp) { this.connectionSignUp = connectionSignUp; } public SocialAuthenticationFilterPostProcessor getSocialAuthenticationFilterPostProcessor() { return socialAuthenticationFilterPostProcessor; } public void setSocialAuthenticationFilterPostProcessor(SocialAuthenticationFilterPostProcessor socialAuthenticationFilterPostProcessor) { this.socialAuthenticationFilterPostProcessor = socialAuthenticationFilterPostProcessor; } } //將我們自定義的 SpringSocialConfigurer交給spring托管 @Configuration @EnableSocial public class SocialConfig extends SocialConfigurerAdapter { @Bean public SpringSocialConfigurer selfSocialSecurityConfig(){ String processFilterUrl = securityProperties.getSocial().getProcessFilterUrl(); SelfSpringSocialConfig selfSpringSocialConfig = new SelfSpringSocialConfig(processFilterUrl); //指定第三方用戶信息認證不存在的注冊頁 selfSpringSocialConfig.signupUrl(securityProperties.getBrowser().getSiguUpPage()); selfSpringSocialConfig.setConnectionSignUp(connectionSignUp); selfSpringSocialConfig.setSocialAuthenticationFilterPostProcessor(socialAuthenticationFilterPostProcessor); return selfSpringSocialConfig; } }
我們自定義的過濾器后置處理器如下
/** * autor:liman * createtime:2021/8/7 * comment:APP社交登錄認證后置處理器 */ @Component public class AppSocialAuthenticationFilterPostProcessor implements SocialAuthenticationFilterPostProcessor { @Autowired private AuthenticationSuccessHandler selfAuthenticationSuccessHandler; @Override public void process(SocialAuthenticationFilter socialAuthenticationFilter) { socialAuthenticationFilter.setAuthenticationSuccessHandler(selfAuthenticationSuccessHandler); } }
這里需要總結一下之前的社交登錄中用戶注冊綁定的操作。
在之前的社交登錄中,如果spring social發現用戶是第一次登錄,則會跳轉到相關的頁面,這個頁面我們其實也可以自己定義并配置
@Configuration @EnableSocial public class SocialConfig extends SocialConfigurerAdapter { @Bean public SpringSocialConfigurer selfSocialSecurityConfig(){ String processFilterUrl = securityProperties.getSocial().getProcessFilterUrl(); SelfSpringSocialConfig selfSpringSocialConfig = new SelfSpringSocialConfig(processFilterUrl); //指定第三方用戶信息認證不存在的注冊頁 selfSpringSocialConfig.signupUrl(securityProperties.getBrowser().getSiguUpPage()); selfSpringSocialConfig.setConnectionSignUp(connectionSignUp); selfSpringSocialConfig.setSocialAuthenticationFilterPostProcessor(socialAuthenticationFilterPostProcessor); return selfSpringSocialConfig; } @Bean public ProviderSignInUtils providerSignInUtils(ConnectionFactoryLocator connectionFactoryLocator){ return new ProviderSignInUtils(connectionFactoryLocator, getUsersConnectionRepository(connectionFactoryLocator)); } }
我們配置的代碼中,可以自定義頁面路徑,我們自定義頁面如下(一個簡單的登錄綁定頁面)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登錄</title> </head> <body> <h3>Demo注冊頁</h3> <form action="user/regist" method="post"> <table> <tr> <td>用戶名:</td> <td><input type="text" name="username"></td> </tr> <tr> <td>密碼:</td> <td><input type="password" name="password"></td> </tr> <tr> <td colspan="2"> <button type="submit" name="type" value="regist">注冊</button> <button type="submit" name="type" value="binding">綁定</button> </td> </tr> </table> </form> </body> </html>
在用戶第一次跳轉到這個頁面的用戶選擇注冊,或者綁定,都會請求/user/register接口,這個接口借助providerSignInUtils完成會話中的用戶數據更新
@Autowired private ProviderSignInUtils providerSignInUtils; @PostMapping("/register") public void userRegister(@RequestBody User user, HttpServletRequest request) { //利用providerSignInUtils,將注冊之后的用戶信息,關聯到會話中 providerSignInUtils.doPostSignUp(user.getId(),new ServletWebRequest(request)); }
在跳轉之前,spring social已經幫我們將用戶信息存入會話(在SocialAuthenticationFilter
中可以看到相關代碼)
//以下代碼位于:org.springframework.social.security.SocialAuthenticationFilter#doAuthentication private Authentication doAuthentication(SocialAuthenticationService<?> authService, HttpServletRequest request, SocialAuthenticationToken token) { try { if (!authService.getConnectionCardinality().isAuthenticatePossible()) return null; token.setDetails(authenticationDetailsSource.buildDetails(request)); Authentication success = getAuthenticationManager().authenticate(token); Assert.isInstanceOf(SocialUserDetails.class, success.getPrincipal(), "unexpected principle type"); updateConnections(authService, token, success); return success; } catch (BadCredentialsException e) { // connection unknown, register new user? if (signupUrl != null) { //這里就是將社交用戶信息存入會話 // store ConnectionData in session and redirect to register page sessionStrategy.setAttribute(new ServletWebRequest(request), ProviderSignInAttempt.SESSION_ATTRIBUTE, new ProviderSignInAttempt(token.getConnection())); throw new SocialAuthenticationRedirectException(buildSignupUrl(request)); } throw e; } }
但是基于前后端分離,且并沒有會話對象交互的系統,這種方式并不適用,因為并不存在會話,如何處理,需要用其他方案,其實我們可以在驗證碼登錄的改造中受到啟發,將用戶數據存入會話即可,我們自定義實現一個providerSignInUtils
將用戶信息存入Redis即可。
1、將第三方用戶數據存入Redis的工具類
/** * autor:liman * createtime:2021/8/7 * comment:app端用戶信息存入Redis的工具類 */ @Component public class AppSignUpUtils { public static final String SOCIAL_REDIS_USER_PREFIX = "self:security:social:connectionData"; @Autowired private RedisTemplate<Object, Object> redisTemplate; @Autowired private UsersConnectionRepository usersConnectionRepository; @Autowired private ConnectionFactoryLocator connectionFactoryLocator; public void saveConnectionData(WebRequest webRequest, ConnectionData connectionData) { redisTemplate.opsForValue().set(getKey(webRequest), connectionData, 10, TimeUnit.MINUTES); } /** * 將用戶與數據庫中的信息進行綁定 * @param request * @param userId */ public void doPostSignUp(WebRequest request,String userId){ String key = getKey(request); if(!redisTemplate.hasKey(key)){ throw new RuntimeException("無法找到緩存的用戶社交賬號信息"); } ConnectionData connectionData = (ConnectionData) redisTemplate.opsForValue().get(key); //根據ConnectionData實例化創建一個Connection Connection<?> connection = connectionFactoryLocator.getConnectionFactory(connectionData.getProviderId()) .createConnection(connectionData); //將數據庫中的用戶與Redis中的用戶信息關聯 usersConnectionRepository.createConnectionRepository(userId).addConnection(connection); } /** * 獲取設備id作為key * * @param webRequest * @return */ public String getKey(WebRequest webRequest) { String deviceId = webRequest.getHeader("deviceId"); if (StringUtils.isBlank(deviceId)) { throw new RuntimeException("設備id不能為空"); } return SOCIAL_REDIS_USER_PREFIX + deviceId; } }
2、復寫掉原來的配置類
為了避免對原有代碼的侵入性處理,這里我們需要自定義一個實現BeanPostProcessor
接口的類
/** * autor:liman * createtime:2021/8/7 * comment:由于app端的社交用戶綁定,不能采用跳轉,也不能操作會話,需要用自定義的providerSignUpUtils工具類 * 因此需要定義一個后置處理器,針對SpringSocialConfigurer進行一些后置處理 */ @Component public class AppSpringSocialConfigurerPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return null; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(StringUtils.equals(beanName,"selfSocialSecurityConfig")){ SelfSpringSocialConfig configurer = (SelfSpringSocialConfig) bean; //復寫掉原有的SelfSpringSocialConfig的signupUrl configurer.signupUrl("/app/social/signup"); return configurer; } return bean; } }
針對上述的請求路徑,我們也要寫一個對應路徑的controller處理方法
@RestController @Slf4j public class AppSecurityController { @Autowired private ProviderSignInUtils providerSignInUtils; @Autowired private AppSignUpUtils appSignUpUtils; @GetMapping("/app/social/signup") @ResponseStatus(HttpStatus.UNAUTHORIZED) public BaseResponse getSocialUserInfo(HttpServletRequest request){ BaseResponse result = new BaseResponse(StatusCode.Success); log.info("【app模式】開始獲取會話中的第三方用戶信息"); //先從其中拿出數據,畢竟這個時候還沒有完全跳轉,下一個會話,就沒有該數據了 Connection<?> connectionFromSession = providerSignInUtils.getConnectionFromSession(new ServletWebRequest(request)); SocialUserInfo socialUserInfo = new SocialUserInfo(); socialUserInfo.setProviderId(connectionFromSession.getKey().getProviderId()); socialUserInfo.setProviderUserId(connectionFromSession.getKey().getProviderUserId()); socialUserInfo.setNickName(connectionFromSession.getDisplayName()); socialUserInfo.setHeadImg(connectionFromSession.getImageUrl()); //轉存到自己的工具類中 appSignUpUtils.saveConnectionData(new ServletWebRequest(request),connectionFromSession.createData()); result.setData(socialUserInfo); return result; } }
對于用戶注冊的接口也需要做調整
@PostMapping("/register") public void userRegister(@RequestBody User user, HttpServletRequest request) { //如果是瀏覽器的應用利用providerSignInUtils,將注冊之后的用戶信息,關聯到會話中 providerSignInUtils.doPostSignUp(user.getId(),new ServletWebRequest(request)); //如果是app的應用,則利用appSignUpUtils 將注冊之后的用戶信息,關聯到會話中 appSignUpUtils.doPostSignUp(new ServletWebRequest(request),user.getId()); }
以上是“springsecurity如何實現基于token的認證方式”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。