Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.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+;LDAP+;CustomLdapAuthoritiesPopulator+;记住_Java_Spring_Spring Security_Ldap_Remember Me - Fatal编程技术网

Java Spring Security+;LDAP+;CustomLdapAuthoritiesPopulator+;记住

Java Spring Security+;LDAP+;CustomLdapAuthoritiesPopulator+;记住,java,spring,spring-security,ldap,remember-me,Java,Spring,Spring Security,Ldap,Remember Me,我对spring security有点问题:) 我的目标是什么: 使用自定义角色配置LDAP身份验证、从数据库获取和记忆我功能 做了什么: public class MyRememberMeProcessingFilter extends RememberMeProcessingFilter { private myService; @Override protected void onSuccessfulAuthentication(HttpServletReq

我对spring security有点问题:)

我的目标是什么: 使用自定义角色配置LDAP身份验证、从数据库获取和记忆我功能

做了什么:

public class MyRememberMeProcessingFilter extends RememberMeProcessingFilter { 
    private myService; 

    @Override 
    protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) { 
        // perform some custom logic when the user has been 'remembered' & authenticated - e.g. update a login count etc 
        this.myService.doSomeCustomBusinessLogic(authResult.getName()); 

        super.onSuccessfulAuthentication(request, response, authResult); 
    } 
} 
<custom-authentication-provider /> 
  • LDAP验证:确定
  • 数据库中广告用户的自定义角色:OK
  • 记住我:失败
我的问题是: “记住我”很好用,成功创建了持久登录表,它可以很好地存储令牌。但当用户返回网站时,spring会显示“未授权”页面

我认为这是因为“记住我”对我的自定义角色和从LDAP获取角色一无所知

问题是:如何告诉“记住我”通过我的CustomLdapAuthoritiesPopulator获得角色

my applicationContext.xml

<bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
    <constructor-arg value="ldap://ldap.forumsys.com:389"/>
    <property name="userDn" value="cn=read-only-admin,dc=example,dc=com"/>
    <property name="password" value="password"/>
</bean>

<bean name="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/db"/>
    <property name="username" value="username"/>
    <property name="password" value="password"/>
</bean>

<bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
    <constructor-arg>
        <bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
            <constructor-arg ref="contextSource"/>
            <property name="userDnPatterns">
                <list>
                    <value>uid={0},dc=example,dc=com</value>
                </list>
            </property>
        </bean>
    </constructor-arg>
    <constructor-arg>
        <bean class="my.extra.CustomLdapAuthoritiesPopulator"/>
    </constructor-arg>
</bean>

<bean id="tokenRepository"
      class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
    <property name="createTableOnStartup" value="false"/>
    <property name="dataSource" ref="myDataSource"/>
</bean>

<security:authentication-manager>
    <security:authentication-provider ref="ldapAuthProvider"/>
</security:authentication-manager>

<security:http auto-config="true" use-expressions="true">
    <security:access-denied-handler error-page="/403"/>
    <security:intercept-url pattern="/login*" access="permitAll()"/>
    <security:intercept-url pattern="/favicon.ico" access="permitAll()"/>
    <security:intercept-url pattern="/resources/**" access="permitAll()"/>
    <security:intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
    <security:form-login login-page='/login' login-processing-url="/j_spring_security_check"
                         default-target-url="/" authentication-failure-url="/login?fail"/>
    <security:remember-me key="_spring_security_remember_me" token-validity-seconds="14400"
                          token-repository-ref="tokenRepository"
                          user-service-ref="ldapUserService"/>

</security:http>

<security:ldap-user-service id="ldapUserService" server-ref="contextSource"
                            group-search-base="dc=example,dc=com"
                            group-search-filter="ou={0})"
                            user-search-base="dc=example,dc=com"
                            user-search-filter="uid={0}"/>

uid={0},dc=example,dc=com
在调试期间,当用户返回时,不会调用CustomLdapAuthoritiesPopulator。 我添加了代码来检查用户的角色(在欢迎页面和自定义403页面上)

如果您使用的身份验证提供程序不使用
UserDetailsService
(例如LDAP提供程序),那么除非您的应用程序上下文中也有UserDetailsService bean,否则它将无法工作

尝试在
应用程序上下文.xml
中添加以下内容:-

加上。来自Spring文档

如果有任何
ConfigAttribute.getAttribute()
以前缀开头,表示它是一个角色,则进行表决。默认前缀字符串为
角色
,但这可能会被覆盖为任何值。它也可以设置为空,这意味着本质上任何属性都将被投票。如下文进一步描述的,空前缀的效果可能不是很理想

如果没有以角色前缀开头的配置属性,则放弃投票。如果与以角色前缀开头的
ConfigAttribute
完全匹配,则投票授予访问权限。如果没有与以角色前缀开头的ConfigAttribute完全匹配的GrantedAuthority,则投票拒绝访问

所有比较和前缀都区分大小写。

现在,配置一个Spring
AccessDecisionManager
,它利用上面的两个投票者,以确定用户是否被授予访问资源的正确权限

rememberprocessingfilter
以包括用户返回站点并被应用程序“记住”时希望运行的任何自定义业务逻辑

别忘了添加:

public class MyRememberMeProcessingFilter extends RememberMeProcessingFilter { 
    private myService; 

    @Override 
    protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) { 
        // perform some custom logic when the user has been 'remembered' & authenticated - e.g. update a login count etc 
        this.myService.doSomeCustomBusinessLogic(authResult.getName()); 

        super.onSuccessfulAuthentication(request, response, authResult); 
    } 
} 
<custom-authentication-provider /> 

这确保了“记住我”实际上被用作身份验证提供程序-即,当您的用户返回之前要求记住的内容时,这会将“记住我”添加到检查用户是否已通过身份验证的提供程序列表中。

使用错误的解决方案

<security:ldap-user-service/>

若要从数据库应用自定义角色以实现“记住我”功能

仍然需要实现自定义UserDetailsService,并在“记住我”部分中引用它

<security:http>
....
<security:remember-me key="_spring_security_remember_me" token-validity-seconds="14400"
                          token-repository-ref="tokenRepository"
                          user-service-ref="rememberMeUserDetailsService"/>
</security:http>

<bean id="rememberMeUserDetailsService" class="gpb.extra.RememberMeUserDetailsService"/>

....
这有点棘手,但很有效,我的数据库存储每个用户名,因为它存储角色。因此,我可以检查没有LDAP的任何用户

package gpb.extra;

import gpb.database.models.User;
import gpb.database.utils.HibernateUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

public class RememberMeUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    Collection<GrantedAuthority> authorities = new HashSet<>();
    List<User> users = HibernateUtils.get(User.class, username, "username");
    if (users.size() == 0) {
        throw new UsernameNotFoundException("User not found");
    } else {
        User existingUser = users.get(0);
        if (!existingUser.getRoles().isEmpty()) {
            List<String> roles = Arrays.asList(existingUser.getRoles().split(","));
            roles.forEach(t -> authorities.add(new SimpleGrantedAuthority(t.trim())));
        }
    }

    boolean enabled = true;
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;

    return new org.springframework.security.core.userdetails.User(
            username, "password", enabled, accountNonExpired,
            credentialsNonExpired, accountNonLocked, authorities);
}
}
包gpb.extra;
导入gpb.database.models.User;
导入gpb.database.utils.HibernateUtils;
导入org.springframework.security.core.GrantedAuthority;
导入org.springframework.security.core.authority.SimpleGrantedAuthority;
导入org.springframework.security.core.userdetails.userdetails;
导入org.springframework.security.core.userdetails.userdetails服务;
导入org.springframework.security.core.userdetails.UsernameNotFoundException;
导入java.util.array;
导入java.util.Collection;
导入java.util.HashSet;
导入java.util.List;
公共类RememberMemberUserDetailsService实现UserDetailsService{
@凌驾
public UserDetails loadUserByUsername(字符串用户名)引发UsernameNotFoundException{
收集权限=新的HashSet();
List users=HibernateUtils.get(User.class,用户名,“username”);
if(users.size()==0){
抛出新的UsernameNotFoundException(“未找到用户”);
}否则{
User existingUser=users.get(0);
如果(!existingUser.getRoles().isEmpty()){
List roles=Arrays.asList(existingUser.getRoles().split(“,”);
roles.forEach(t->authorities.add(新的SimpleGrantedAuthority(t.trim()));
}
}
布尔启用=真;
布尔值accountNonExpired=true;
布尔CredentialsNoExpired=true;
布尔值accountNonLocked=true;
返回新的org.springframework.security.core.userdetails.User(
用户名,“密码”,已启用,AccountNoExpired,
凭证无支出、账户无锁定、权限);
}
}
代码演示了主要思想


非常感谢@OO7为我指明了正确的方向,并提供了惊人的帮助:)

你对上述问题有什么答案吗?如果没有,请尝试我的答案并访问我提供的链接,以获取有关“记住我”身份验证的详细信息。尝试在我的答案中使用新链接。我解决了问题,稍后将发布答案。提供的链接不包含任何与“LDAP记住我”实现相关的信息。我不知道如何将此应用于我的配置。另外,很多标记为“不推荐”的东西我正在使用SpringSecurity3.2.4.Release我已经更新了我的答案。请尝试此更新。RoleVoter将替换我的“use expressions=true”,我不想要它,所有控制器的
<security:http>
....
<security:remember-me key="_spring_security_remember_me" token-validity-seconds="14400"
                          token-repository-ref="tokenRepository"
                          user-service-ref="rememberMeUserDetailsService"/>
</security:http>

<bean id="rememberMeUserDetailsService" class="gpb.extra.RememberMeUserDetailsService"/>
package gpb.extra;

import gpb.database.models.User;
import gpb.database.utils.HibernateUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

public class RememberMeUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    Collection<GrantedAuthority> authorities = new HashSet<>();
    List<User> users = HibernateUtils.get(User.class, username, "username");
    if (users.size() == 0) {
        throw new UsernameNotFoundException("User not found");
    } else {
        User existingUser = users.get(0);
        if (!existingUser.getRoles().isEmpty()) {
            List<String> roles = Arrays.asList(existingUser.getRoles().split(","));
            roles.forEach(t -> authorities.add(new SimpleGrantedAuthority(t.trim())));
        }
    }

    boolean enabled = true;
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;

    return new org.springframework.security.core.userdetails.User(
            username, "password", enabled, accountNonExpired,
            credentialsNonExpired, accountNonLocked, authorities);
}
}