Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Spring Security进行未经授权的预身份验证_Java_Spring_Security_Authentication_Spring Security - Fatal编程技术网

Java 使用Spring Security进行未经授权的预身份验证

Java 使用Spring Security进行未经授权的预身份验证,java,spring,security,authentication,spring-security,Java,Spring,Security,Authentication,Spring Security,我的要求是: 在我的应用程序中,当用户通过登录屏幕(而不是使用Spring Security)登录时,身份验证第一次由定制的第三方API执行。现在,我们得到了一些使用rest服务调用的增强。根据要求,在从应用程序发出任何rest调用之前,我们需要根据数据库重新验证用户。由于用户在使用登录屏幕登录时已经进行了验证,并且请求中提供了这些详细信息,我计划使用spring security重新验证用户(预验证场景)。我们在应用程序中没有为用户定义任何角色。因此,无需担心角色。我已经阅读了参考手册,但没有

我的要求是:

在我的应用程序中,当用户通过登录屏幕(而不是使用Spring Security)登录时,身份验证第一次由定制的第三方API执行。现在,我们得到了一些使用rest服务调用的增强。根据要求,在从应用程序发出任何rest调用之前,我们需要根据数据库重新验证用户。由于用户在使用登录屏幕登录时已经进行了验证,并且请求中提供了这些详细信息,我计划使用spring security重新验证用户(预验证场景)。我们在应用程序中没有为用户定义任何角色。因此,无需担心角色。我已经阅读了参考手册,但没有获得更多关于如何进一步操作的信息。我理解的一件事是,在用户通过定制的第三方API进行身份验证后,我们需要以某种方式告知spring上下文。就连我也在谷歌上搜索了一下,但找不到一个适合我要求的好例子。 如果有人能指导我如何从一个例子开始,那就太好了

我只需要告诉spring上下文“嘿..!这个用户已经过身份验证,这样他就可以在自定义的第三方API验证用户的凭据后调用rest服务了。


我不应该更改现有的初始身份验证过程。我应该只使用已验证的用户信息,并进一步使用spring安全性来重新验证用户


我的问题与spring参考手册中提到的问题类似

请不要用单行回答(除非有正确的答案) 如果你能给我看一个例子或伪代码,那就太好了

提前谢谢。

你试过这个吗

SecurityContextHolder.getContext().setAuthenticated(true);

我建议从Spring安全性到第三方登录页面建立一个“桥梁”。如果您使用Spring,我认为这是最好的工作方式

也就是说,您有一个登录处理程序,可以将用户重定向到第三方登录页面。登录后,用户将重定向回web应用

这就是你的意思吗?听起来不错吗?有意义吗

如果是这样,您可以使用获得一些帮助:

<security:http entry-point-ref="legacyEntryPoint">

通常,这意味着每当相关http调用试图访问您的应用程序时,这就是处理请求的入口点。在您的情况下,legacyEntryPoint是一个类,您将实现该类,它将检查用户是否经过身份验证;如果没有,它将用户重定向到第三方登录系统,否则它将使用已知的“令牌”“使用你的应用程序


希望有帮助

对于第一次身份验证,我希望您可以使用一些输入值(如用户名/密码)调用第三方API,它将返回true/false。如果是这样,您可以编写自己的AuthenticationProvider,如下所示。并调用第三方身份验证,如下所示。Spring安全框架将自动设置SecurityContextHolder.getContext().setAuthenticated(true或false);因此。你不必设置这个

        public class MyAuthenticationProvider implements AuthenticationProvider {

            @Override
            public Authentication authenticate(Authentication authentication) throws AuthenticationException {

                String user = (String) authentication.getPrincipal();
                String password = (String) authentication.getCredentials();

                List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
                authorities.add(new SimpleGrantedAuthority("ROLE_ONE"));
                authorities.add(new SimpleGrantedAuthority("ROLE_TWO"));

                UsernamePasswordAuthenticationToken authenticationToken = null;



                if (<your 3rd party authentication result == true>)) {
                    authenticationToken = new UsernamePasswordAuthenticationToken(user, password, authorities);
                } else {
                    throw new BadCredentialsException("Invalid credentials supplied. Please try again.");
                }
                return authenticationToken;
            }


            @Override
            public boolean supports(Class<?> authentication) {
                boolean supports = authentication.isAssignableFrom(UsernamePasswordAuthenticationToken.class);
                return supports;
            }

        }

我也在做类似的事情。我正在为无状态REST后端进行身份验证,因此我希望用户进行一次身份验证,然后对于每个后续请求,身份验证必须是透明的。我用代币来做这个。登录时,用户提供的凭据用于身份验证和生成令牌(尽管最终我们希望使用外部服务来获取令牌)。令牌作为标头返回。然后angularjs前端在每个后续REST调用中发送令牌。后端将检查令牌的有效性,如果令牌有效,则将“authenticated”标记为true

以下是我的security-context.xml:

<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="
  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-4.0.xsd">

<http use-expressions="true" 
      entry-point-ref="restAuthenticationEntryPoint"
      create-session="stateless">
    <intercept-url pattern="/secured/extreme/**" access="hasRole('ROLE_SUPERVISOR')"/>
    <intercept-url pattern="/secured/**" access="isAuthenticated()" />
    <intercept-url pattern="/j_spring_security_check" requires-channel="https" access="permitAll"/>
    <intercept-url pattern="/logon.jsp" requires-channel="https" access="permitAll"/>
    <sec:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
</http>

<beans:bean id="restAuthenticationEntryPoint" class="com.company.project.authentication.security.RestAuthenticationEntryPoint" />

<beans:bean id="authenticationTokenProcessingFilter" class="com.company.project.authentication.security.AuthenticationTokenProcessingFilter" >
    <beans:property name="authenticationManager" ref="authenticationManager" />
    <beans:property name="userDetailsServices"> 
                <beans:list>
                    <beans:ref bean="inMemoryUserDetailsService" />
                    <beans:ref bean="tmpUserDetailsService" />
                </beans:list>
    </beans:property>

</beans:bean>

<beans:bean id="tmpUserDetailsService" class="com.company.project.authentication.security.TokenUserDetailsServiceImpl" />

<user-service id="inMemoryUserDetailsService">
            <user name="temporary" password="temporary" authorities="ROLE_SUPERVISOR" />
            <user name="user" password="userPass" authorities="ROLE_USER" />
</user-service>

<authentication-manager alias="authenticationManager">
    <!-- Use some hard-coded values for development -->
    <authentication-provider user-service-ref="inMemoryUserDetailsService" />
    <authentication-provider ref='companyLdapProvider' />
</authentication-manager>

对于身份验证筛选器,我将UsernamePasswordAuthenticationFilter子类化。当它是一个登录请求时,就会发生与身份验证提供者的身份验证,然后生成一个令牌。如果从报头读取令牌,则检查该令牌以进行身份验证。这是我的身份验证过滤器(它还没有准备好生产,但它可以让您了解您可以做什么):

公共类AuthenticationTokenProcessingFilter扩展了UsernamePasswordAuthenticationFilter{
//~静态字段/初始值设定项=====================================================================================
私有静态最终字符串头\u AUTH\u TOKEN=“X-AUTH-TOKEN”;
私有静态最终记录器Logger=LoggerFactory.getLogger(AuthenticationTokenProcessingFilter.class);
private List userDetailsServices=new ArrayList();
//~z~施工人员===================================================================================================
公共身份验证TokenProcessingFilter(){
超级();
}
//~方法========================================================================================================
@凌驾
public void doFilter(ServletRequest-req、ServletResponse-res、FilterChain-chain)抛出IOException,
ServletException{
HttpServletRequest请求=(HttpServletRequest)请求;
HttpServletResponse=(HttpServletResponse)res;
String authToken=this.extractAuthTokenFromRequest(请求);
if(authToken==null){
super.doFilter(请求、res、链);
返回;
}
字符串userName=TokenUtils.getUserNameFromToken(authToken);
如果(用户名!=null){
UserDetails UserDetails=loadUserByUsername(用户名);
if(TokenUtils.validateToken(authToken,userDetails)){
用户名
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="
  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-4.0.xsd">

<http use-expressions="true" 
      entry-point-ref="restAuthenticationEntryPoint"
      create-session="stateless">
    <intercept-url pattern="/secured/extreme/**" access="hasRole('ROLE_SUPERVISOR')"/>
    <intercept-url pattern="/secured/**" access="isAuthenticated()" />
    <intercept-url pattern="/j_spring_security_check" requires-channel="https" access="permitAll"/>
    <intercept-url pattern="/logon.jsp" requires-channel="https" access="permitAll"/>
    <sec:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
</http>

<beans:bean id="restAuthenticationEntryPoint" class="com.company.project.authentication.security.RestAuthenticationEntryPoint" />

<beans:bean id="authenticationTokenProcessingFilter" class="com.company.project.authentication.security.AuthenticationTokenProcessingFilter" >
    <beans:property name="authenticationManager" ref="authenticationManager" />
    <beans:property name="userDetailsServices"> 
                <beans:list>
                    <beans:ref bean="inMemoryUserDetailsService" />
                    <beans:ref bean="tmpUserDetailsService" />
                </beans:list>
    </beans:property>

</beans:bean>

<beans:bean id="tmpUserDetailsService" class="com.company.project.authentication.security.TokenUserDetailsServiceImpl" />

<user-service id="inMemoryUserDetailsService">
            <user name="temporary" password="temporary" authorities="ROLE_SUPERVISOR" />
            <user name="user" password="userPass" authorities="ROLE_USER" />
</user-service>

<authentication-manager alias="authenticationManager">
    <!-- Use some hard-coded values for development -->
    <authentication-provider user-service-ref="inMemoryUserDetailsService" />
    <authentication-provider ref='companyLdapProvider' />
</authentication-manager>
public class AuthenticationTokenProcessingFilter extends UsernamePasswordAuthenticationFilter {
//~ Static fields/initializers =====================================================================================

private static final String HEADER_AUTH_TOKEN = "X-Auth-Token";    
private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationTokenProcessingFilter.class);

private List<UserDetailsService> userDetailsServices = new ArrayList<UserDetailsService>();
//~ Constructors ===================================================================================================

public AuthenticationTokenProcessingFilter() {
    super();
}

//~ Methods ========================================================================================================
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
                ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

        String authToken = this.extractAuthTokenFromRequest(request);
        if (authToken == null) {
            super.doFilter(request,  res,  chain);
            return;
        }
        String userName = TokenUtils.getUserNameFromToken(authToken);

        if (userName != null) {

                UserDetails userDetails = loadUserByUsername(userName);

                if (TokenUtils.validateToken(authToken, userDetails)) {

                        UsernamePasswordAuthenticationToken authentication =
                                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                }
        }

        chain.doFilter(request, response);
}

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    if (!request.getMethod().equals("POST")) {
        throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
    }

    UsernamePasswordAuthenticationToken authRequest = authenticateWithForm(request, response);
    // Allow subclasses to set the "details" property
    setDetails(request, authRequest);

    Authentication authentication = this.getAuthenticationManager().authenticate(authRequest);

    if (authentication.isAuthenticated()) {
        try {
            String authToken = TokenUtils.createToken(obtainUsername(request), obtainPassword(request));
            LOGGER.info("Setting HTTP header {} = {}", HEADER_AUTH_TOKEN, authToken);
            response.addHeader(HEADER_AUTH_TOKEN, authToken);
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();                
            LOGGER.info("authorities = {}", authorities);
            // Now we should make an in-memory table of the token and userdetails for later use 
        } catch(Exception e) {
            LOGGER.warn("Error creating token for authentication. Authorization token head cannot be created.", e);
        }

    }

    return authentication;
}

protected UsernamePasswordAuthenticationToken authenticateWithForm(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    String username = obtainUsername(request);
    String password = obtainPassword(request);

    if (username == null) {
        username = "";
    }

    if (password == null) {
        password = "";
    }

    username = username.trim();

    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

    return authRequest;
}

private String extractAuthTokenFromRequest(HttpServletRequest httpRequest) {
        /* Get token from header */
        String authToken = httpRequest.getHeader(HEADER_AUTH_TOKEN);

        /* If token not found get it from request parameter */
        if (authToken == null) {
                authToken = httpRequest.getParameter("token");
        }

        return authToken;
}

public List<UserDetailsService> getUserDetailsServices() {
    return userDetailsServices;
}

public void setUserDetailsService(UserDetailsService userDetailsService) {
    this.userDetailsServices.add(userDetailsService);
}

public void setUserDetailsServices(List<UserDetailsService> users) {
    if (users != null) {
        this.userDetailsServices.clear();
        this.userDetailsServices.addAll(users);
    }
}
private UserDetails loadUserByUsername(String username) {
    UserDetails user = null;
    List<Exception> exceptions = new ArrayList<Exception>();
    for (UserDetailsService service: userDetailsServices) {
        try {
            user = service.loadUserByUsername(username);
            break;
        } catch (Exception e) {
            LOGGER.warn("Could not load user by username {} with service {}", username, service.getClass().getName());
            LOGGER.info("Exception is: ",e);
            exceptions.add(e);
        }
    }
    if (user == null && !exceptions.isEmpty()) {
        throw new AuthenticationException(exceptions.get(0));
    }
    return user;
}
}