无需登录即可在应用程序外部访问Spring

时间:2016-10-08 10:09:45

标签: spring spring-mvc spring-security spring-restcontroller

我有一个使用spring 4的应用程序,所有方法都是rest(使用RestController)。我使用spring-security(基于角色)登录和验证URL。

下面是我的spring-security.xml

<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/security
                           http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    <security:http auto-config="true" use-expressions="true">
        <security:form-login login-page="/public/login"
            default-target-url="/auth/userhome" authentication-failure-url="/public/fail2login" always-use-default-target="true"/>
        <security:intercept-url pattern="/index.jsp" access="permitAll" />
        <security:intercept-url pattern="/public/**" access="permitAll" />
        <security:intercept-url pattern="/resources/**" access="permitAll" />
        <security:logout logout-success-url="/public/logout" />

        <security:intercept-url pattern="/auth/**" access="fullyAuthenticated" />
        <security:intercept-url pattern="/**" access="denyAll" />

        <security:session-management
            session-fixation-protection="migrateSession" invalid-session-url="/login">
            <security:concurrency-control
                max-sessions="1" expired-url="/login" />
        </security:session-management>
    </security:http>

    <security:authentication-manager>
        <security:authentication-provider
            user-service-ref="hbUserDetailService">
            <security:password-encoder hash="plaintext" />
        </security:authentication-provider>
    </security:authentication-manager>
</beans>

服务:

package com.arat.budget.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.arat.budget.dao.UserDao;
import com.arat.budget.model.UserRoles;
import com.arat.budget.model.Users;

    @Service
    public class HbUserDetailsService implements UserDetailsService {
        @Autowired
        private UserDao userDao;

        @SuppressWarnings("unchecked")
        @Transactional
        public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {

            Users user = userDao.findByUserName(username);
            List<GrantedAuthority> authorities = buildUserAuthority(user.getUserRoleses());

            return buildUserForAuthentication(user, authorities);

        }

        // Converts com.mkyong.users.model.User user to
        // org.springframework.security.core.userdetails.User
        private User buildUserForAuthentication(Users user, List<GrantedAuthority> authorities) {
            return new User(user.getUsername(), user.getPassword(), user.isEnabled(), true, true, true, authorities);
        }

        private List<GrantedAuthority> buildUserAuthority(Set<UserRoles> userRoles) {

            Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

            // Build user's authorities
            for (UserRoles userRole : userRoles) {
                setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
            }

            List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);

            return Result;
        }

        public UserDao getUserDao() {
            return userDao;
        }

        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }

    }
@RestController
public class PostAuthController {
    @RequestMapping(value = "/auth/userhome", method = RequestMethod.GET)
    public String executeSecurity(ModelMap model, Principal principal) {

        String name = principal.getName();
        model.addAttribute("author", name);
        model.addAttribute("message",
                "Welcome To Login Form Based Spring Security Example!!!");
        return "auth/welcome";

    }
}

我可以毫无问题地登录。但我有一个带/ auth / employee / {id}和请求映射的控制器。

因为/ auth / **是完全认证的,所以其他应用程序如何访问其余端点

@RestController
@RequestMapping(value="/auth")
public class EmployeeController{

@RequestMapping("/employee/{id}",method=RequestMethod.GET)
public List<Employee> getEmployee(@PathVariable int id){
    return userDao.getEmployee(id);
}
}

请问您如何在没有登录的情况下在另一个应用程序中访问/ auth / employee / 1001?

注意:我正在使用图块在此应用程序中呈现页面

2 个答案:

答案 0 :(得分:0)

您可以为此使用基本身份验证。扩展BasicAuthenticationEntryPoint类并创建它的自定义实现。

public class CustomBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

    @Override
    public void commence(final HttpServletRequest request, 
            final HttpServletResponse response, 
            final AuthenticationException authException) throws IOException, ServletException {
        //Authentication failed, send error response.
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName() + "");

        PrintWriter writer = response.getWriter();
        writer.println("HTTP Status 401 : " + authException.getMessage());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        setRealmName("MY_TEST_REALM");
        super.afterPropertiesSet();
    }
}

有关详细信息,请参阅this

希望这有帮助。

答案 1 :(得分:0)

我得到了解决方案。

我创建了一个单独的api url,它只显示资源并添加了基本的auth过滤器。

我的spring-security.xml如下所示。

<?xml version="1.0"?>
<beans:beans xmlns:beans="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="http://www.springframework.org/schema/security"
    xmlns:p="http://www.springframework.org/schema/p"
    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/beans
                            http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                            http://www.springframework.org/schema/security
                            http://www.springframework.org/schema/security/spring-security-3.2.xsd">

    <!-- Oauth start -->
    <http pattern="/oauth/token" create-session="stateless"
        authentication-manager-ref="clientAuthenticationManager">
        <intercept-url pattern="/oauth/token"
            access="IS_AUTHENTICATED_FULLY" />
        <anonymous enabled="false" />
        <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
        <custom-filter ref="clientCredentialsTokenEndpointFilter"
            after="BASIC_AUTH_FILTER" />
        <access-denied-handler ref="oauthAccessDeniedHandler" />
    </http>

    <http pattern="/api/**" create-session="never"
        entry-point-ref="oauthAuthenticationEntryPoint"
        access-decision-manager-ref="accessDecisionManager">
        <anonymous enabled="false" />
        <intercept-url pattern="/api/**" access="ROLE_APP" />
        <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
        <access-denied-handler ref="oauthAccessDeniedHandler" />
    </http>


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

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

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

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

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

    <authentication-manager id="clientAuthenticationManager">
        <authentication-provider user-service-ref="clientDetailsUserService" />
    </authentication-manager>


    <authentication-manager alias="authenticationManager">
        <authentication-provider
            user-service-ref="hbUserDetailService">
            <password-encoder hash="plaintext" />
        </authentication-provider>
        <!-- <authentication-provider>
            <jdbc-user-service data-source-ref="spring_db_DataSource"/>
        </authentication-provider> -->
    </authentication-manager>

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


    <beans:bean id="tokenStore"
        class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

    <beans:bean id="tokenServices"
        class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
        <beans:property name="tokenStore" ref="tokenStore" />
        <beans:property name="supportRefreshToken" value="true" />
        <beans:property name="accessTokenValiditySeconds" value="120" />
        <beans:property name="clientDetailsService" ref="clientDetails" />
    </beans:bean>

    <beans:bean id="userApprovalHandler"
        class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
        <beans:property name="tokenServices" ref="tokenServices" />
    </beans: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">
        <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>

    <!-- <global-method-security
        pre-post-annotations="enabled" proxy-target-class="true">
        <expression-handler ref="oauthExpressionHandler" />
    </global-method-security> -->

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

    <!-- Oauth end -->

    <!-- Form based security starts-->                          
    <http auto-config="true" use-expressions="true"
        authentication-manager-ref="authenticationManagerForRest">
        <form-login login-page="/public/login"
            default-target-url="/auth/userhome" authentication-failure-url="/public/fail2login"
            always-use-default-target="true" />
        <intercept-url pattern="/index.jsp"
            access="permitAll" />
        <intercept-url pattern="/public/**"
            access="permitAll" />
        <intercept-url pattern="/resources/**"
            access="permitAll" />
        <logout logout-success-url="/public/logout" />
        <access-denied-handler error-page="/403.html"/>
        <intercept-url pattern="/auth/**"
            access="fullyAuthenticated" />
        <intercept-url pattern="/**" access="denyAll" />

        <session-management
            session-fixation-protection="migrateSession" invalid-session-url="/login">
            <concurrency-control
                max-sessions="1" expired-url="/login" />
        </session-management>
    </http>

    <authentication-manager alias="authenticationManagerForRest">
        <authentication-provider
            user-service-ref="hbUserDetailService">
            <password-encoder hash="plaintext" />
        </authentication-provider>
    </authentication-manager>

    <!-- Form based security ends -->
</beans:beans>

部署项目并获取访问令牌

localhost:8080/<context>/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=<uer>&password=<password>

它将提供访问令牌,我们可以使用它来隐藏其余的终点