OAuth2.0通过token获取受保护资源的解析

假设我们的accessToken是这样的

{
    "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,由以下返回结果可知,他是一个包含了大量信息的类.而每一个信息块里面又有着接口和实现类.

@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-16ee0ba24b01

返回结果如下

{
    "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"
}

首先我们需要写一个资源配置类

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter

其中这个@EnableResourceServer实际上帮我们加入了一个过滤器(应该说所有的业务模块都要有一个资源配置类来开启这个过滤器)org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter

在他的源码中有一个doFilter

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整个对象的方法都有调用.

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()提取出来的.

转载于:https://my.oschina.net/u/3768341/blog/1865734

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值