Spring Security OAuth2 实现登录互踢

首先登录互踢,就是同一账号同时只能在一处登录,所以实现方式就是没登录一次就更新一次token,确保之前的token失效

这里有两种方式

1.修改源码,将生成机制修改

下面屏蔽的代码就是修改的代码,这个在网上挺多的 参考:Spring Security OAuth2 实现登录互踢 - 云+社区 - 腾讯云 (tencent.com)

 

// 重写生成方法
    @Override
    @Transactional
    public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
        OAuth2AccessToken existingAccessToken = this.tokenStore.getAccessToken(authentication);
        OAuth2RefreshToken refreshToken = null;
        if (existingAccessToken != null) {
            // 屏蔽token是否过期
//            if (!existingAccessToken.isExpired()) {
//                this.tokenStore.storeAccessToken(existingAccessToken, authentication);
//                return existingAccessToken;
//            }

//            if (existingAccessToken.getRefreshToken() != null) {
//                refreshToken = existingAccessToken.getRefreshToken();
//                this.tokenStore.removeRefreshToken(refreshToken);
//            }
            this.tokenStore.removeAccessToken(existingAccessToken);
        }

        if (refreshToken == null) {
            refreshToken = this.createRefreshToken(authentication);
        }
        else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
            ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken)refreshToken;
            if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {
                refreshToken = this.createRefreshToken(authentication);
            }
        }

        OAuth2AccessToken accessToken = this.createAccessToken(authentication, refreshToken);
        this.tokenStore.storeAccessToken(accessToken, authentication);
        refreshToken = accessToken.getRefreshToken();
        if (refreshToken != null) {
            this.tokenStore.storeRefreshToken(refreshToken, authentication);
        }

        return accessToken;
    }

这样基本就满足了这个需求,但是在开发过程中遇到一个问题,就是源码修改后在怎么部署到项目中

刚开始不知道,将有关的源码全部复制到项目中

如图

 其实这样是比较重的方式,而且也没有必要将所有代码都引入

只需要引入最重用的那个文件,也就是 DefaultTokenServices.java,包括文件目录都不变

直接运行,就可以看到效果了,就不贴图了

如果觉得这种方式太重,可以重写接口的方式

就是我要说的

直接上接口代码,这里直接给出 登录互踢和登录的接口和实现

package com.adao.security.contorller;

import com.alibaba.fastjson.JSONObject;
import com.adao.security.common.ApiResult;
import com.adao.security.common.OperationLog;
import com.adao.security.service.AuthService;
import io.swagger.annotations.Api;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.security.Principal;
import java.util.Map;

/**
 * @author adao
 * @version 1.0
 * @date 2021/8/12
 * @description 认证控制相关接口
 */
@RestController
@RequestMapping("/oauth")
@Api(tags = "认证管理接口")
@Log4j2
public class AuthController {

    /**
     * 认证服务对象
     */
    @Resource
    private AuthService authService;

    /**
     * 重写/oauth/token接口
     *
     * @param principal
     * @param parameters
     * @return accessToken
     */
    @PostMapping("/token")
    public ApiResult postAccessToken(Principal principal,
                                     @RequestParam Map<String, String> parameters) {
        // 判断用户名明码是否正确,是否被锁定等逻辑
        String username = parameters.get("username");
        String password = parameters.get("password");

        return authService.createAccessToken(principal, parameters);
    }

    /**
     * 认证注销
     *
     * @param params token值
     * @return authLogout
     */
    @PostMapping(value = "/logout")
    @OperationLog(operModul = "安全认证-登录注销", operType = "LogOut", operDesc = "认证token信息注销清除")
    public ApiResult logOut(@RequestBody JSONObject params) {
        String accessToken = params.getString("accessToken");
        return authService.logout(accessToken);
    }
}
AuthServiceImpl
package com.adao.security.service.impl;

import com.google.common.collect.Maps;
import com.adao.security.common.ApiCode;
import com.adao.security.common.ApiResult;
import com.adao.security.service.AuthService;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.stereotype.Service;
import org.springframework.web.HttpRequestMethodNotSupportedException;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author adao
 * @version 1.0
 * @date 2021/8/12
 * @description Oauth2认证逻辑实现类
 */
@Service("authService")
@Log4j2
public class AuthServiceImpl implements AuthService {

    @Autowired
    private RedisTokenStore redisTokenStore;

    @Autowired
    private RedisTokenStore tokenStore;

    @Autowired
    private TokenEndpoint tokenEndpoint;

    @Override
    public ApiResult createAccessToken(Principal principal, Map<String, String> parameters) {

        // 刷新并废弃掉当前token再重新生成token
        OAuth2AccessToken accessToken = null;
        try {
            accessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
            String discardToken = accessToken.getValue();
            // 注销token
            logout(discardToken);
            // 重新生成token
            accessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
            log.info("create accessToken" + accessToken);
        } catch (HttpRequestMethodNotSupportedException e) {
            log.error("create accessToken error" + e.getMessage());
            return ApiResult.fail("鉴权失败");
        }

        // token信息
        Map<String, Object> resultMap = Maps.newLinkedHashMap();
        resultMap.put("access_token", accessToken.getValue());
        resultMap.put("refresh_token", accessToken.getRefreshToken().getValue());
        resultMap.put("token_type", accessToken.getTokenType());
        resultMap.put("expires_in", accessToken.getExpiresIn());
        resultMap.put("scope", org.apache.commons.lang3.StringUtils.join(accessToken.getScope(), ","));
        resultMap.putAll(accessToken.getAdditionalInformation());
        // 权限信息

        List<String> list = getAuthoritiesList(accessToken);
        if (list != null && !list.isEmpty()) {
            resultMap.put("authorities", list);
            return ApiResult.ok(resultMap);
        } else {
            return ApiResult.fail("权限信息获取异常", resultMap);
        }
    }


    /**
     * 通过accessToken注销redis中用户注册token信息
     *
     * @param accessToken
     * @return ApiResult
     */
    @Override
    public ApiResult logout(String accessToken) {
        try {
            if (StringUtils.isNotBlank(accessToken)) {
                OAuth2AccessToken oAuth2AccessToken = redisTokenStore.readAccessToken(accessToken);
                if (null != oAuth2AccessToken) {
                    redisTokenStore.removeAccessToken(oAuth2AccessToken);
                    OAuth2RefreshToken oAuth2RefreshToken = oAuth2AccessToken.getRefreshToken();
                    redisTokenStore.removeRefreshToken(oAuth2RefreshToken);
                    redisTokenStore.removeAccessTokenUsingRefreshToken(oAuth2RefreshToken);
                    log.info("注销成功. accessToken : {}, RefreshToken: {}", accessToken, oAuth2RefreshToken);
                } else {
                    log.info("注销失败. 无效accessToken : {}", accessToken);
                    return ApiResult.fail(ApiCode.ACCESS_TOKEN_INVALID);
                }
            }
            return ApiResult.ok();
        } catch (Exception e) {
            log.error("用户注销错误 :" + e.getMessage());
            return ApiResult.fail("用户注销错误 : " + e.getMessage());
        }
    }

    /**
     * 获取用户权限信息
     *
     * @param accessToken
     * @return List
     */
    private List<String> getAuthoritiesList(OAuth2AccessToken accessToken) {
        // 权限信息
        Collection<? extends GrantedAuthority> authorities =
                tokenStore.readAuthentication(accessToken).getUserAuthentication().getAuthorities();
        List<String> AuthoritiesList = new ArrayList<>();
        for (GrantedAuthority authority : authorities) {
            AuthoritiesList.add(authority.getAuthority());
        }
        return AuthoritiesList;
    }
}

 然后尝试多次登录 查看token变化还有redis中的token数据

-----------------------------

补充,上面

第一种是通过逻辑来解决互踢的需求,

第二种是通过源码的方式

如果以上两种都不想用还有第三种

如下,重写接口并且同时修改源码 

AuthController2
package com.adao.security.contorller;


import com.alibaba.fastjson.JSONObject;
import com.adao.security.common.ApiResult;
import com.adao.security.common.OperationLog;
import com.adao.security.service.AuthService;
import io.swagger.annotations.Api;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.*;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.InvalidRequestException;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.security.Principal;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.UUID;


/**
 * @author adao
 * @version 1.0
 * @date 2021/8/12
 * @description 认证控制相关接口
 */
@RestController
@RequestMapping("/oauth")
@Api(tags = "认证管理接口")
@Log4j2
public class AuthController2 {

    /**
     * 认证服务对象
     */
    @Resource
    private AuthService authService;

    @Autowired
    private RedisTokenStore tokenStore;

    @Autowired
    private TokenEndpoint tokenEndpoint;

    @Autowired
    private ClientDetailsService clientDetailsService;

//    @Autowired
//    private CreateTokenServiceHandler tokenServices;

    @Autowired
    public ApplicationContext applicationContext;

    private OAuth2RequestFactory oAuth2RequestFactory;

    private OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator();

    private TokenGranter tokenGranter;

    private boolean supportRefreshToken = false;

    private int refreshTokenValiditySeconds = 60 * 60 * 60;
    private int accessTokenValiditySeconds = 60 * 60;

    private TokenEnhancer accessTokenEnhancer;

    /**
     * 认证注销
     *
     * @param params token值
     * @return authLogout
     */
    @PostMapping(value = "/logout")
    @OperationLog(operModul = "安全认证-登录注销", operType = "LogOut", operDesc = "认证token信息注销清除")
    public ApiResult logOut(@RequestBody JSONObject params) {
        String accessToken = params.getString("accessToken");
        return authService.logout(accessToken);
    }

    /**
     * 重写login接口
     *
     * @param principal
     * @param parameters
     * @return
     * @throws HttpRequestMethodNotSupportedException
     */
    @PostMapping("/token")
    public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal,
                                                             @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        String username = parameters.get("username");
        String password = parameters.get("password");
        String grantType = parameters.get("grant_type");
        String scope = parameters.get("scope");

//        OAuth2AccessToken accessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();

        String clientId = this.getClientId(principal);
        ClientDetails client = clientDetailsService.loadClientByClientId(clientId);

        TokenRequest tokenRequest = new TokenRequest(parameters, clientId, Collections.singleton(scope), grantType);

        tokenRequest = getTokenRequest(principal, parameters, tokenRequest);

        if (this.isRefreshTokenRequest(parameters)) {
            tokenRequest.setScope(OAuth2Utils.parseParameterList((String) parameters.get("scope")));
        }

        OAuth2Request storedOAuth2Request = tokenRequest.createOAuth2Request(client);

//        storedOAuth2Request.getRefreshTokenRequest().s

        OAuth2Authentication oa = new OAuth2Authentication(storedOAuth2Request, null);
//        OAuth2AccessToken token = tokenServices.createAccessToken(oa);
        OAuth2AccessToken token = createAccessToken(oa);

//        OAuth2AccessToken token = tokenServices.createAccessToken(oa);

//        CreateTokenServiceHandler tokenServiceHandler = applicationContext.getBean(CreateTokenServiceHandler.class);
//        OAuth2AccessToken token = tokenServiceHandler.createAccessToken(oa);


        System.out.println("client :" + client.getClientId());
        System.out.println("token###" + token);
        return this.getResponse(token);

    }

    //    private TokenRequest createTokenRequest(parameters, clientId, Collections.singleton(scope), grantType){
//        TokenRequest tokenRequest = new TokenRequest(parameters, clientId, Collections.singleton(scope), grantType);
//    }
    @Transactional
    public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
        OAuth2AccessToken existingAccessToken = this.tokenStore.getAccessToken(authentication);
        OAuth2RefreshToken refreshToken = null;
        if (existingAccessToken != null) {
//            if (!existingAccessToken.isExpired()) {
//                this.tokenStore.storeAccessToken(existingAccessToken, authentication);
//                return existingAccessToken;
//            }
//
//            if (existingAccessToken.getRefreshToken() != null) {
//                refreshToken = existingAccessToken.getRefreshToken();
//                this.tokenStore.removeRefreshToken(refreshToken);
//            }

            this.tokenStore.removeAccessToken(existingAccessToken);
        }

        if (refreshToken == null) {
            refreshToken = createRefreshToken(authentication);
        } else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
            ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken) refreshToken;
            if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {
                refreshToken = createRefreshToken(authentication);
            }
        }

        OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
        this.tokenStore.storeAccessToken(accessToken, authentication);
        refreshToken = accessToken.getRefreshToken();
        if (refreshToken != null) {
            this.tokenStore.storeRefreshToken(refreshToken, authentication);
        }

        return accessToken;
    }

    private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
        DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
        int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());
        if (validitySeconds > 0) {
            token.setExpiration(new Date(System.currentTimeMillis() + (long) validitySeconds * 1000L));
        }

        token.setRefreshToken(refreshToken);
        token.setScope(authentication.getOAuth2Request().getScope());
        return (OAuth2AccessToken) (accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token);
    }

    private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) {
        if (!this.isSupportRefreshToken(authentication.getOAuth2Request())) {
            return null;
        } else {
            int validitySeconds = this.getRefreshTokenValiditySeconds(authentication.getOAuth2Request());
            String value = UUID.randomUUID().toString();
            return (OAuth2RefreshToken) (validitySeconds > 0 ? new DefaultExpiringOAuth2RefreshToken(value, new Date(System.currentTimeMillis() + (long) validitySeconds * 1000L)) : new DefaultOAuth2RefreshToken(value));
        }
    }

    protected int getAccessTokenValiditySeconds(OAuth2Request clientAuth) {
        if (this.clientDetailsService != null) {
            ClientDetails client = this.clientDetailsService.loadClientByClientId(clientAuth.getClientId());
            Integer validity = client.getAccessTokenValiditySeconds();
            if (validity != null) {
                return validity;
            }
        }

        return this.accessTokenValiditySeconds;
    }


    protected boolean isSupportRefreshToken(OAuth2Request clientAuth) {
        if (this.clientDetailsService != null) {
            ClientDetails client = this.clientDetailsService.loadClientByClientId(clientAuth.getClientId());
            return client.getAuthorizedGrantTypes().contains("refresh_token");
        } else {
            return this.supportRefreshToken;
        }
    }

    protected int getRefreshTokenValiditySeconds(OAuth2Request clientAuth) {
        if (this.clientDetailsService != null) {
            ClientDetails client = this.clientDetailsService.loadClientByClientId(clientAuth.getClientId());
            Integer validity = client.getRefreshTokenValiditySeconds();
            if (validity != null) {
                return validity;
            }
        }

        return this.refreshTokenValiditySeconds;
    }

    private TokenRequest getTokenRequest(Principal principal, @RequestParam Map<String, String> parameters, TokenRequest tokenRequest) {
        if (!(principal instanceof Authentication)) {
            throw new InsufficientAuthenticationException("There is no client authentication. Try adding an appropriate authentication filter.");
        } else {
            String clientId = this.getClientId(principal);
            ClientDetails authenticatedClient = this.getClientDetailsService().loadClientByClientId(clientId);
//            TokenRequest tokenRequest = createTokenRequest(parameters, authenticatedClient);
            if (clientId != null && !clientId.equals("") && !clientId.equals(tokenRequest.getClientId())) {
                throw new InvalidClientException("Given client ID does not match authenticated client");
            } else {
                if (authenticatedClient != null) {
                    this.oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
                }

                if (!StringUtils.hasText(tokenRequest.getGrantType())) {
                    throw new InvalidRequestException("Missing grant type");
                } else if (tokenRequest.getGrantType().equals("implicit")) {
                    throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
                } else {
                    if (this.isAuthCodeRequest(parameters) && !tokenRequest.getScope().isEmpty()) {
                        log.debug("Clearing scope of incoming token request");
                        tokenRequest.setScope(Collections.emptySet());
                    }

                    if (this.isRefreshTokenRequest(parameters)) {
                        tokenRequest.setScope(OAuth2Utils.parseParameterList((String) parameters.get("scope")));
                    }

                }
            }
            return tokenRequest;
        }
    }


    protected String getClientId(Principal principal) {
        Authentication client = (Authentication) principal;
        if (!client.isAuthenticated()) {
            throw new InsufficientAuthenticationException("The client is not authenticated.");
        } else {
            String clientId = client.getName();
            if (client instanceof OAuth2Authentication) {
                clientId = ((OAuth2Authentication) client).getOAuth2Request().getClientId();
            }

            return clientId;
        }
    }

    private ResponseEntity<OAuth2AccessToken> getResponse(OAuth2AccessToken accessToken) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Cache-Control", "no-store");
        headers.set("Pragma", "no-cache");
        headers.set("Content-Type", "application/json;charset=UTF-8");
        return new ResponseEntity(accessToken, headers, HttpStatus.OK);
    }

    private boolean isRefreshTokenRequest(Map<String, String> parameters) {
        return "refresh_token".equals(parameters.get("grant_type")) && parameters.get("refresh_token") != null;
    }

    protected ClientDetailsService getClientDetailsService() {
        return this.clientDetailsService;
    }

    protected OAuth2RequestFactory getOAuth2RequestFactory() {
        return this.oAuth2RequestFactory;
    }

    private boolean isAuthCodeRequest(Map<String, String> parameters) {
        return "authorization_code".equals(parameters.get("grant_type")) && parameters.get("code") != null;
    }

    protected TokenGranter getTokenGranter() {
        return this.tokenGranter;
    }

}

 最后还有一种方式和第三种类似,但是没有验证 

onAuthenticationSuccess
package com.adao.security.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;

/**
 * @author adao
 * @version 1.0
 * @date 2021/8/13
 * @description 群组表(Group)表控制层
 */
@Log4j2
@Component
public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private AuthorizationServerTokenServices authorizationServerTokenServices;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        // 1. 从请求头中获取 ClientId
        String header = request.getHeader("Authorization");
        if (header == null || !header.startsWith("Basic ")) {
            throw new UnapprovedClientAuthenticationException("请求头中无client信息");
        }

        String[] tokens = this.extractAndDecodeHeader(header, request);
        String clientId = tokens[0];
        String clientSecret = tokens[1];
        TokenRequest tokenRequest = null;
        // 2. 通过 ClientDetailsService 获取 ClientDetails
        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
        // 3. 校验 ClientId和 ClientSecret的正确性
        if (clientDetails == null) {
            throw new UnapprovedClientAuthenticationException("clientId:" + clientId + "对应的信息不存在");
        } else if (!StringUtils.equals(clientDetails.getClientSecret(), clientSecret)) {
            throw new UnapprovedClientAuthenticationException("clientSecret不正确");
        } else {
            // 4. 通过 TokenRequest构造器生成 TokenRequest
            tokenRequest = new TokenRequest(new HashMap<>(), clientId, clientDetails.getScope(), "custom");
        }

        // 5. 通过 TokenRequest的 createOAuth2Request方法获取 OAuth2Request
        OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
        // 6. 通过 Authentication和 OAuth2Request构造出 OAuth2Authentication
        OAuth2Authentication auth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);

        // 7. 通过 AuthorizationServerTokenServices 生成 OAuth2AccessToken
        OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(auth2Authentication);

        // 8. 返回 Token
        log.info("登录成功");
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(new ObjectMapper().writeValueAsString(token));
    }

    private String[] extractAndDecodeHeader(String header, HttpServletRequest request) {
        byte[] base64Token = header.substring(6).getBytes(StandardCharsets.UTF_8);

        byte[] decoded;
        try {
            decoded = Base64.getDecoder().decode(base64Token);
        } catch (IllegalArgumentException var7) {
            throw new BadCredentialsException("Failed to decode basic authentication token");
        }

        String token = new String(decoded, StandardCharsets.UTF_8);
        int delim = token.indexOf(":");
        if (delim == -1) {
            throw new BadCredentialsException("Invalid basic authentication token");
        } else {
            return new String[]{token.substring(0, delim), token.substring(delim + 1)};
        }
    }
}

  

  

原文地址:https://www.cnblogs.com/adao21/p/15143787.html