OAuth2.0經過token獲取受保護資源的解析

假設咱們的accessToken是這樣的spring

{
    "access_token": "ffb71ed0-5e48-44bc-b4aa-16ee0ba24b01",
    "token_type": "bearer",
    "refresh_token": "70220a36-3419-4c48-a60e-2d80b0f1774f",
    "expires_in": 28799,
    "scope": "app"
}安全

獲取當前用戶的Authentication,Authentication是一個接口,具體實現類是OAuth2Authentication,由如下返回結果可知,他是一個包含了大量信息的類.而每個信息塊裏面又有着接口和實現類.session

@GetMapping("/user-me")
public Authentication principal() {
   Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
   log.debug("user-me:{}", authentication.getName());
   return authentication;
}

請求http://127.0.0.1:50075/user-me?access_token=ffb71ed0-5e48-44bc-b4aa-16ee0ba24b01app

返回結果以下less

{
    "authorities": [
        {
            "authority": "back:menu:set2role"
        },
        {
            "authority": "mail:update"
        },
        {
            "authority": "back:permission:delete"
        },
        {
            "authority": "role:permission:byroleid"
        },
        {
            "authority": "back:menu:save"
        },
        {
            "authority": "back:menu:query"
        },
        {
            "authority": "ip:black:query"
        },
        {
            "authority": "ip:black:save"
        },
        {
            "authority": "file:del"
        },
        {
            "authority": "ip:black:delete"
        },
        {
            "authority": "mail:query"
        },
        {
            "authority": "back:user:query"
        },
        {
            "authority": "back:role:permission:set"
        },
        {
            "authority": "sms:query"
        },
        {
            "authority": "back:role:query"
        },
        {
            "authority": "back:permission:query"
        },
        {
            "authority": "back:role:save"
        },
        {
            "authority": "back:user:role:set"
        },
        {
            "authority": "log:query"
        },
        {
            "authority": "file:query"
        },
        {
            "authority": "back:menu:update"
        },
        {
            "authority": "back:role:update"
        },
        {
            "authority": "back:role:delete"
        },
        {
            "authority": "back:user:password"
        },
        {
            "authority": "ROLE_SUPER_ADMIN"
        },
        {
            "authority": "back:menu:delete"
        },
        {
            "authority": "back:user:update"
        },
        {
            "authority": "menu:byroleid"
        },
        {
            "authority": "mail:save"
        },
        {
            "authority": "user:role:byuid"
        },
        {
            "authority": "back:permission:save"
        },
        {
            "authority": "back:permission:update"
        }
    ],
    "details": {
        "remoteAddress": "127.0.0.1",
        "sessionId": null,
        "tokenValue": "ffb71ed0-5e48-44bc-b4aa-16ee0ba24b01",
        "tokenType": "Bearer",
        "decodedDetails": null
    },
    "authenticated": true,
    "userAuthentication": {
        "authorities": [
            {
                "authority": "back:menu:set2role"
            },
            {
                "authority": "mail:update"
            },
            {
                "authority": "back:permission:delete"
            },
            {
                "authority": "role:permission:byroleid"
            },
            {
                "authority": "back:menu:save"
            },
            {
                "authority": "back:menu:query"
            },
            {
                "authority": "ip:black:query"
            },
            {
                "authority": "ip:black:save"
            },
            {
                "authority": "file:del"
            },
            {
                "authority": "ip:black:delete"
            },
            {
                "authority": "mail:query"
            },
            {
                "authority": "back:user:query"
            },
            {
                "authority": "back:role:permission:set"
            },
            {
                "authority": "sms:query"
            },
            {
                "authority": "back:role:query"
            },
            {
                "authority": "back:permission:query"
            },
            {
                "authority": "back:role:save"
            },
            {
                "authority": "back:user:role:set"
            },
            {
                "authority": "log:query"
            },
            {
                "authority": "file:query"
            },
            {
                "authority": "back:menu:update"
            },
            {
                "authority": "back:role:update"
            },
            {
                "authority": "back:role:delete"
            },
            {
                "authority": "back:user:password"
            },
            {
                "authority": "ROLE_SUPER_ADMIN"
            },
            {
                "authority": "back:menu:delete"
            },
            {
                "authority": "back:user:update"
            },
            {
                "authority": "menu:byroleid"
            },
            {
                "authority": "mail:save"
            },
            {
                "authority": "user:role:byuid"
            },
            {
                "authority": "back:permission:save"
            },
            {
                "authority": "back:permission:update"
            }
        ],
        "details": {
            "grant_type": "password",
            "scope": "app",
            "client_secret": "system",
            "client_id": "system",
            "username": "admin|USERNAME"
        },
        "authenticated": true,
        "principal": {
            "id": 1,
            "username": "admin",
            "password": "$2a$10$3uOoX1ps14CxuotogUoDreW8zXJOZB9XeGdrC/xDV36hhaE8Rn9HO",
            "nickname": "測試1",
            "headImgUrl": "",
            "phone": "",
            "sex": 1,
            "enabled": true,
            "type": "APP",
            "createTime": "2018-01-17T16:56:59.000+0000",
            "updateTime": "2018-01-17T16:57:01.000+0000",
            "sysRoles": [
                {
                    "id": 1,
                    "code": "SUPER_ADMIN",
                    "name": "超級管理員",
                    "createTime": "2018-01-19T20:32:16.000+0000",
                    "updateTime": "2018-01-19T20:32:18.000+0000"
                }
            ],
            "permissions": [
                "back:menu:set2role",
                "mail:update",
                "back:permission:delete",
                "role:permission:byroleid",
                "back:menu:save",
                "back:menu:query",
                "ip:black:query",
                "ip:black:save",
                "file:del",
                "ip:black:delete",
                "mail:query",
                "back:user:query",
                "back:role:permission:set",
                "sms:query",
                "back:role:query",
                "back:permission:query",
                "back:role:save",
                "back:user:role:set",
                "log:query",
                "file:query",
                "back:menu:update",
                "back:role:update",
                "back:role:delete",
                "back:user:password",
                "back:menu:delete",
                "back:user:update",
                "menu:byroleid",
                "mail:save",
                "user:role:byuid",
                "back:permission:save",
                "back:permission:update"
            ],
            "credentialsNonExpired": true,
            "accountNonExpired": true,
            "accountNonLocked": true
        },
        "credentials": null,
        "name": "admin"
    },
    "credentials": "",
    "principal": {
        "id": 1,
        "username": "admin",
        "password": "$2a$10$3uOoX1ps14CxuotogUoDreW8zXJOZB9XeGdrC/xDV36hhaE8Rn9HO",
        "nickname": "測試1",
        "headImgUrl": "",
        "phone": "",
        "sex": 1,
        "enabled": true,
        "type": "APP",
        "createTime": "2018-01-17T16:56:59.000+0000",
        "updateTime": "2018-01-17T16:57:01.000+0000",
        "sysRoles": [
            {
                "id": 1,
                "code": "SUPER_ADMIN",
                "name": "超級管理員",
                "createTime": "2018-01-19T20:32:16.000+0000",
                "updateTime": "2018-01-19T20:32:18.000+0000"
            }
        ],
        "permissions": [
            "back:menu:set2role",
            "mail:update",
            "back:permission:delete",
            "role:permission:byroleid",
            "back:menu:save",
            "back:menu:query",
            "ip:black:query",
            "ip:black:save",
            "file:del",
            "ip:black:delete",
            "mail:query",
            "back:user:query",
            "back:role:permission:set",
            "sms:query",
            "back:role:query",
            "back:permission:query",
            "back:role:save",
            "back:user:role:set",
            "log:query",
            "file:query",
            "back:menu:update",
            "back:role:update",
            "back:role:delete",
            "back:user:password",
            "back:menu:delete",
            "back:user:update",
            "menu:byroleid",
            "mail:save",
            "user:role:byuid",
            "back:permission:save",
            "back:permission:update"
        ],
        "credentialsNonExpired": true,
        "accountNonExpired": true,
        "accountNonLocked": true
    },
    "clientOnly": false,
    "oauth2Request": {
        "clientId": "system",
        "scope": [
            "app"
        ],
        "requestParameters": {
            "grant_type": "password",
            "scope": "app",
            "client_id": "system",
            "username": "admin|USERNAME"
        },
        "resourceIds": [],
        "authorities": [],
        "approved": true,
        "refresh": false,
        "redirectUri": null,
        "responseTypes": [],
        "extensions": {},
        "grantType": "password",
        "refreshTokenRequest": null
    },
    "name": "admin"
}ide

首先咱們須要寫一個資源配置類測試

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter

其中這個@EnableResourceServer實際上幫咱們加入了一個過濾器(應該說全部的業務模塊都要有一個資源配置類來開啓這個過濾器)org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilterui

在他的源碼中有一個doFilterthis

public class OAuth2AuthenticationProcessingFilter implements Filter, InitializingBean
private TokenExtractor tokenExtractor = new BearerTokenExtractor();
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    boolean debug = logger.isDebugEnabled();
    HttpServletRequest request = (HttpServletRequest)req;
    HttpServletResponse response = (HttpServletResponse)res;

    try {
        //從request中解析PreAuthenticatedAuthenticationToken(注意這裏並非OAuth2Authentication)
        Authentication authentication = this.tokenExtractor.extract(request);
        if(authentication == null) {
            if(this.stateless && this.isAuthenticated()) {
                if(debug) {
                    logger.debug("Clearing security context.");
                }

                SecurityContextHolder.clearContext();
            }

            if(debug) {
                logger.debug("No token in request, will continue chain.");
            }
        } else {
            request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
            if(authentication instanceof AbstractAuthenticationToken) {
                AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken)authentication;
                needsDetails.setDetails(this.authenticationDetailsSource.buildDetails(request));
            }
            
            Authentication authResult = this.authenticationManager.authenticate(authentication);
            if(debug) {
                logger.debug("Authentication success: " + authResult);
            }

            this.eventPublisher.publishAuthenticationSuccess(authResult);
            //此處爲把authResult放入安全容器中,此處比較重要
            SecurityContextHolder.getContext().setAuthentication(authResult);
        }
    } catch (OAuth2Exception var9) {
        SecurityContextHolder.clearContext();
        if(debug) {
            logger.debug("Authentication request failed: " + var9);
        }

        this.eventPublisher.publishAuthenticationFailure(new BadCredentialsException(var9.getMessage(), var9), new PreAuthenticatedAuthenticationToken("access-token", "N/A"));
        this.authenticationEntryPoint.commence(request, response, new InsufficientAuthenticationException(var9.getMessage(), var9));
        return;
    }

    chain.doFilter(request, response);
}

TokenExtractor也是一個接口,咱們能夠看到,他是由BearerTokenExtractor實現類來實現的.基本上BearerTokenExtractor整個對象的方法都有調用.debug

public class BearerTokenExtractor implements TokenExtractor {
    private static final Log logger = LogFactory.getLog(BearerTokenExtractor.class);

    public BearerTokenExtractor() {
    }

    public Authentication extract(HttpServletRequest request) {
        String tokenValue = this.extractToken(request);
        if(tokenValue != null) {
            PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(tokenValue, "");
            return authentication;
        } else {
            return null;
        }
    }
    /**
     *從request參數查找認證
    */
    protected String extractToken(HttpServletRequest request) {
        String token = this.extractHeaderToken(request);
        if(token == null) {
            logger.debug("Token not found in headers. Trying request parameters.");
            token = request.getParameter("access_token");
            if(token == null) {
                logger.debug("Token not found in request parameters.  Not an OAuth2 request.");
            } else {
                request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, "Bearer");
            }
        }

        return token;
    }
    /**
     *從request的header開始查找認證
    */
    protected String extractHeaderToken(HttpServletRequest request) {
        Enumeration headers = request.getHeaders("Authorization");

        String value;
        do {
            if(!headers.hasMoreElements()) {
                return null;
            }

            value = (String)headers.nextElement();
        } while(!value.toLowerCase().startsWith("Bearer".toLowerCase()));

        String authHeaderValue = value.substring("Bearer".length()).trim();
        request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, value.substring(0, "Bearer".length()).trim());
        int commaIndex = authHeaderValue.indexOf(44);
        if(commaIndex > 0) {
            authHeaderValue = authHeaderValue.substring(0, commaIndex);
        }

        return authHeaderValue;
    }
}

SecurityContextHolder.getContext().setAuthentication(authResult);咱們單獨把這個提取出來,在以前的

@GetMapping("/user-me")
public Authentication principal() {
   Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
   log.debug("user-me:{}", authentication.getName());
   return authentication;
}

咱們能夠看到咱們訪問的登陸驗證用戶是從SecurityContextHolder.getContext().getAuthentication()提取出來的.

相關文章
相關標籤/搜索