使用oauth2的Spring安全性向授权URL添加其他参数?

时间:2015-07-22 06:08:36

标签: java spring rest oauth spring-security

我在我的restful Web服务中实现了Spring Security。实际上,我必须在客户端的请求中添加一个额外的参数,并且应该在请求认证/ accessstoken时从服务中获取它。

弹簧security.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
            http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd 
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd ">

        <!-- @author Nagesh.Chauhan(neel4soft@gmail.com) -->  

        <!-- This is default url to get a token from OAuth -->
        <http pattern="/oauth/token" create-session="stateless"
                  authentication-manager-ref="clientAuthenticationManager"
                  xmlns="http://www.springframework.org/schema/security">
            <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
            <anonymous enabled="false" />
            <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
            <!-- include this only if you need to authenticate clients via request 
            parameters -->
            <custom-filter ref="clientCredentialsTokenEndpointFilter" 
                                   after="BASIC_AUTH_FILTER" />
            <access-denied-handler ref="oauthAccessDeniedHandler" />
        </http>

        <!-- This is where we tells spring security what URL should be protected 
        and what roles have access to them -->
        <http pattern="/api/**" create-session="never"
                  entry-point-ref="oauthAuthenticationEntryPoint"
                  access-decision-manager-ref="accessDecisionManager"
                  xmlns="http://www.springframework.org/schema/security">
            <anonymous enabled="false" />
            <intercept-url pattern="/api/**" access="ROLE_APP" />
            <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
            <access-denied-handler ref="oauthAccessDeniedHandler" />
        </http>


        <bean id="oauthAuthenticationEntryPoint"
                  class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
            <property name="realmName" value="test" />
        </bean>

        <bean id="clientAuthenticationEntryPoint"
                  class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
            <property name="realmName" value="test/client" />
            <property name="typeName" value="Basic" />
        </bean>

        <bean id="oauthAccessDeniedHandler"
                  class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />

        <bean id="clientCredentialsTokenEndpointFilter"
                  class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
            <property name="authenticationManager" ref="clientAuthenticationManager" />
        </bean>

        <bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
                  xmlns="http://www.springframework.org/schema/beans">
            <constructor-arg>
                <list>
                    <bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
                    <bean class="org.springframework.security.access.vote.RoleVoter" />
                    <bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
                </list>
            </constructor-arg>
        </bean>

        <authentication-manager id="clientAuthenticationManager"
                                    xmlns="http://www.springframework.org/schema/security">
            <authentication-provider user-service-ref="clientDetailsUserService" />
        </authentication-manager>

        <!-- Custom User details service which is provide the user data -->
        <bean id="customUserDetailsService"
              class="com.weekenter.www.service.impl.CustomUserDetailsService" />

        <authentication-manager alias="authenticationManager"
                                xmlns="http://www.springframework.org/schema/security">
            <authentication-provider user-service-ref="customUserDetailsService">  
                <password-encoder hash="plaintext">  
                </password-encoder>
            </authentication-provider> 
        </authentication-manager>




        <bean id="clientDetailsUserService"
                  class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
            <constructor-arg ref="clientDetails" />
        </bean>


        <!-- This defined token store, we have used inmemory tokenstore for now 
        but this can be changed to a user defined one -->
        <bean id="tokenStore"
                  class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

        <!-- This is where we defined token based configurations, token validity 
        and other things -->
        <bean id="tokenServices"
                  class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
            <property name="tokenStore" ref="tokenStore" />
            <property name="supportRefreshToken" value="true" />
            <property name="accessTokenValiditySeconds" value="120" />
            <property name="clientDetailsService" ref="clientDetails" />
        </bean>

        <bean id="userApprovalHandler"
                  class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
            <property name="tokenServices" ref="tokenServices" />
        </bean>

        <oauth:authorization-server
            client-details-service-ref="clientDetails" token-services-ref="tokenServices"
            user-approval-handler-ref="userApprovalHandler">
            <oauth:authorization-code />
            <oauth:implicit />
            <oauth:refresh-token />
            <oauth:client-credentials />
            <oauth:password />
        </oauth:authorization-server>

        <oauth:resource-server id="resourceServerFilter"
                                   resource-id="test" token-services-ref="tokenServices" />

        <oauth:client-details-service id="clientDetails">
            <!-- client -->
            <oauth:client client-id="restapp"
                                  authorized-grant-types="authorization_code,client_credentials"
                                  authorities="ROLE_APP" scope="read,write,trust" secret="secret" />

            <oauth:client client-id="restapp"
                                  authorized-grant-types="password,authorization_code,refresh_token,implicit"
                                  secret="restapp" authorities="ROLE_APP" />

        </oauth:client-details-service>

        <sec:global-method-security
            pre-post-annotations="enabled" proxy-target-class="true">
            <!--you could also wire in the expression handler up at the layer of the 
            http filters. See https://jira.springsource.org/browse/SEC-1452 -->
            <sec:expression-handler ref="oauthExpressionHandler" />
        </sec:global-method-security>

        <oauth:expression-handler id="oauthExpressionHandler" />
        <oauth:web-expression-handler id="oauthWebExpressionHandler" />
    </beans>

CustomUserDetailsS​​ervice

@Service
@Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private LoginDao loginDao;

    public UserDetails loadUserByUsername(String login)
            throws UsernameNotFoundException {

        boolean enabled = true;
        boolean accountNonExpired = true;
        boolean credentialsNonExpired = true;
        boolean accountNonLocked = true;
        com.weekenter.www.entity.User user = null;
        try {
            user = loginDao.getUser(login);
            if (user != null) {
                if (user.getStatus().equals("1")) {
                    enabled = false;
                }
            } else {
                throw new UsernameNotFoundException(login + " Not found !");
            }

        } catch (Exception ex) {
            try {
                throw new Exception(ex.getMessage());
            } catch (Exception ex1) {
            }
        }

        return new User(
                user.getEmail(),
                user.getPassword(),
                enabled,
                accountNonExpired,
                credentialsNonExpired,
                accountNonLocked,
                getAuthorities()
        );
    }

    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authList = getGrantedAuthorities(getRoles());
        return authList;
    }

    public List<String> getRoles() {
        List<String> roles = new ArrayList<String>();
        roles.add("ROLE_APP");
        return roles;
    }

    public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

        for (String role : roles) {
            authorities.add(new SimpleGrantedAuthority(role));
        }
        return authorities;
    }

}

目前我正在请求网址:

http://localhost:8084/Domain/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=anoo@codelynks.com&password=mypass

我会得到回复

{
"access_token":"76e928b2-45e2-4283-88a4-6c01f41b51d3","token_type":"bearer","refresh_token":"8748e8ad-79c1-465d-94fe-13394eea370d","expires_in":119
}

我必须通过添加其他参数deviceToken来增强它。

网址为:

http://localhost:8084/Domain/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=anoo@codelynks.com&password=mypass&deviceToken=something

我通过实施UsernamePasswordAuthenticationFilter来解决问题,但它无效。如何在不影响输出的情况下从Web服务获取deviceToken参数?

2 个答案:

答案 0 :(得分:6)

http://localhost:8084/Domain/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=anoo@codelynks.com&password=mypass&additional_param=abc123

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
log.info("additional_param: " + request.getParameter("additional_param"));

日志将显示

additional_param: abc123

答案 1 :(得分:1)

虽然在横切关注方面使用AOP,但这种方法按预期工作,我认为这是一种有效的方法。

@Aspect 公共课Oauth2Aspect {

@AfterReturning("execution( * org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
public void executeAfterAuthentication() throws Exception {
    System.out.println(":Authentication done");
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    System.out.println(":Authentication done " + request.getParameter("deviceInfo"));
}

}