spring-boot项目使用AD认证登录:

7 篇文章 0 订阅
3 篇文章 0 订阅

spring-boot项目使用AD认证登录:

package com.test.config;

import java.util.Arrays;
import java.util.Collection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.event.LoggerListener;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.web.filter.CharacterEncodingFilter;

import com.test.config.KaptchaAuth.KaptchaAuthenticationFilter;
import com.test.handler.MyAuthenctiationSuccessHandler;




@Configuration
@EnableWebSecurity  
//@EnableGlobalMethodSecurity(securedEnabled = true)  
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	private static final Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class);
	
	@Autowired
	private Environment env;
	
	@Autowired
	MyLdapUserDetailsMapper myLdapUserDetailsMapper;
	
	@Autowired
	private MyAuthenctiationSuccessHandler myAuthenctiationSuccessHandler;
	
	//定义AD认证方法
	@Bean
    public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
        
		final ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(env.getProperty("ldap.domanin"), env.getProperty("ldap.url"));
        provider.setConvertSubErrorCodesToExceptions(true);
        provider.setUseAuthenticationRequestCredentials(true);
        //provider.setAuthoritiesMapper(myAuthoritiesMapper()); //see http://comdynamics.net/blog/544/spring-security-3-integration-with-active-directory-ldap/
        provider.setUseAuthenticationRequestCredentials(true);
        
        //设置角色权限
        provider.setUserDetailsContextMapper(myLdapUserDetailsMapper);
        return provider;
    }

	//引入登录监听类(成功/失败),也可以重写这个类。
    @Bean
    public LoggerListener loggerListener() {
        return new LoggerListener();
    }

    
    //配置地址访问规则
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	http.authorizeRequests()
    	.antMatchers("/**").permitAll().anyRequest().fullyAuthenticated()
        .and().formLogin()
        //.loginPage("/login").defaultSuccessUrl("/").failureUrl("/login").successHandler(myAuthenctiationSuccessHandler)
        ;
    	
    	
    	//解决中文乱码问题
    	CharacterEncodingFilter filter = new CharacterEncodingFilter();
    	filter.setEncoding("UTF-8");
    	filter.setForceEncoding(true);
    	http.addFilterBefore(filter,CsrfFilter.class);
    	
    	//在认证用户名之前认证验证码,如果验证码错误,将不执行用户名和密码的认证
    	//ChannelProcessingFilter通常是用来过滤哪些请求必须用https协议, 哪些请求必须用http协议, 哪些请求随便用哪个协议都行.
    	http.addFilterBefore(new KaptchaAuthenticationFilter("/login", "/login"), ChannelProcessingFilter.class);
    } 

    /*
    
    //配置单个AuthenticationProvider(ActiveDirectoryLdapAuthenticationProvider)
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    	//AuthenticationProvider是做验证工作的组件
        auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
    }*/
    
    
    //配置多种认证方式,即多个AuthenticationProvider(用ProviderManager的Arrays.asList添加多个认证方法)
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        ProviderManager authenticationManager = new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
       //不擦除认证密码,擦除会导致TokenBasedRememberMeServices因为找不到Credentials再调用UserDetailsService而抛出UsernameNotFoundException
        authenticationManager.setEraseCredentialsAfterAuthentication(false);
        return authenticationManager;
    }
    
    
}

设置角色

package com.test.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
import org.springframework.stereotype.Component;

import com.test.domain.SysRole;
import com.test.domain.SysUser;
import com.test.repository.SysRoleRepo;
import com.test.repository.SysUserRepo;
 
/**
 * @author zhu
 * 用户为登录用户设置角色权限
 */
@Component
public class MyLdapUserDetailsMapper extends LdapUserDetailsMapper {
 
	@Autowired
	private SysUserRepo sysUserRepo;
	
	@Autowired
	private SysRoleRepo sysRoleRepo;
	
	@Override
	public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
		
		// 根据username读取用户信息,级联查询用户的角色的名称
		SysUser sysUser = sysUserRepo.findByUsername(username);
		
		//将角色添加到集合里即可  
		List<SimpleGrantedAuthority> WhAuthorities = new ArrayList<>();
		
		if(sysUser == null ) {
			WhAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
		}else {
			// 新建N个角色
			WhAuthorities.add(new SimpleGrantedAuthority(sysUser.getSysrole().getName()));
		}
		return super.mapUserFromContext(ctx, username, WhAuthorities);
	}
}

 

关键的一步:使用已经登录的信息来配置ldapContextSource   ,并配置LdapTemplate   BEAN以供其他地方使用

package com.test.config.ldap;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.security.ldap.authentication.SpringSecurityAuthenticationSource;

@Configuration
public class LdapConfig {

	@Value("${ldap.url}")
    private String ldapUrl;
    @Value("${ldap.baseDn}")
    private String ldapBaseDn;
    
    
    @Value("${ldap.groupSearchBase}")
    private String ldapGroupSearchBase;
    @Value("${ldap.userDnPattern}")
    private String ldapUserDnPattern;
    @Value("${ldap.passwordAttribute}")
    private String ldapPasswordAttribute;

    @Value("${ldap.managerUser}")
    private String ldapManagerUser;
    @Value("${ldap.managerPassword}")
    private String ldapManagerPassword;
	
    @Bean
    public LdapContextSource getContextSource() throws Exception{
        LdapContextSource ldapContextSource = new LdapContextSource();
        ldapContextSource.setUrl(ldapUrl);
        ldapContextSource.setBase(ldapBaseDn);
        //ldapContextSource.setAnonymousReadOnly(true);
        //使用已经登录的信息来配置ldapContextSource
        ldapContextSource.setAuthenticationSource(springSecurityAuthenticationSource());
        return ldapContextSource;
    }

    @Bean
    public LdapTemplate ldapTemplate() throws Exception{
        LdapTemplate ldapTemplate = new LdapTemplate(getContextSource());
        ldapTemplate.setIgnorePartialResultException(true);
        return ldapTemplate;
    }

    @Bean
    public SpringSecurityAuthenticationSource springSecurityAuthenticationSource() {
        return new SpringSecurityAuthenticationSource();
}
}

定义Person类:

package com.test.domain;

import java.security.Timestamp;
import java.util.List;

import javax.naming.Name;

import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;


/* Entry标记,一定要有objectClasses属性,objectClasses属性要跟AD里的一致,可以少几项,但不能多一项。
 * LdapQuery里配置时,不需要再使用.where("objectclass").is("person")指定objectClass
 * base属性查询的时候用不到,只有在新建和更新时,ODM会根据此属性进行匹配
*/
@Entry(objectClasses = {"organizationalPerson", "person" }, base="ou=maksad")
public final  class Person {
		
	
	/** 
	 *  每个entry必须指定@Id字段,类型为javax.naming.Name,其实就是DN。
     * 	但是若在LdapContextSource中指定了base,则DN将会按照base截取相对路径。
     * 	比如,DN为cn=user,ou=users,dc=test,dc=com,base为dc=test,dc=com,则取出的user对象DN为cn=user,ou=users。
     */
    @Id
    private Name dn;
    
    /**
     * 必填属性,帐户名
     */
    private String cn;

    /**
     * 必填属性,姓
     */
    private String sn;
    
    
    


    private String whenCreated;
    
    /**
     * 类型   //如果字段跟AD里的字段不同,就要用@Attribute来找到对应的AD字段
     */
    @Attribute(name = "objectClass")
    private List<String> objectclass;
        
    /**
     * 电话号码
     */
    @Attribute
    private String telephoneNumber;
    
    /**
     * 跟CN一样
     */
    private String sAMAccountName; 

    
    /**
     * 全称
     */
    private String name;
    
    /**
     * 邮箱
     */
    private String mail;
    
    /**
     * 名字
     */
    private String givenName; 
    
    /**
     * 描述
     */
    private String description;
    
    /**
     * 显示名称 
     */
    private String displayName; 
    
    /**
     * 
     */
    private String distinguishedName;
    
    /**
     * 
     */
    private String userAccountControl;
    
    /**
     * 
     */
    private String userPrincipalName;
    
    
    /**
     * 隶属于
     */
    private List<String> memberOf;
    
    

    /**
     * 可选属性
     */
    /*@Attribute(name = "userPassword")
    private String userPassword; */
    
    
    /*@Attribute(name="userPassword", type=Type.BINARY)
    private byte[] userPassword;*/

	public String getDistinguishedName() {
		return distinguishedName;
	}

	public void setDistinguishedName(String distinguishedName) {
		this.distinguishedName = distinguishedName;
	}

	public String getUserPrincipalName() {
		return userPrincipalName;
	}

	public void setUserPrincipalName(String userPrincipalName) {
		this.userPrincipalName = userPrincipalName;
	}

	public String getUserAccountControl() {
		return userAccountControl;
	}

	public void setUserAccountControl(String userAccountControl) {
		this.userAccountControl = userAccountControl;
	}

	public List<String> getObjectclass() {
		return objectclass;
	}

	public void setObjectclass(List<String> objectclass) {
		this.objectclass = objectclass;
	}


	public String getTelephoneNumber() {
		return telephoneNumber;
	}

	public void setTelephoneNumber(String telephoneNumber) {
		this.telephoneNumber = telephoneNumber;
	}


	public Name getDn() {
		return dn;
	}

	public void setDn(Name dn) {
		this.dn = dn;
	}

	public String getSn() {
		return sn;
	}

	public void setSn(String sn) {
		this.sn = sn;
	}

	public String getCn() {
		return cn;
	}

	public void setCn(String cn) {
		this.cn = cn;
	}

	public String getsAMAccountName() {
		return sAMAccountName;
	}

	public void setsAMAccountName(String sAMAccountName) {
		this.sAMAccountName = sAMAccountName;
	}


	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getMail() {
		return mail;
	}

	public void setMail(String mail) {
		this.mail = mail;
	}

	public String getGivenName() {
		return givenName;
	}

	public void setGivenName(String givenName) {
		this.givenName = givenName;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getDisplayName() {
		return displayName;
	}

	public void setDisplayName(String displayName) {
		this.displayName = displayName;
	}

	public List<String> getMemberOf() {
		return memberOf;
	}

	public void setMemberOf(List<String> memberOf) {
		this.memberOf = memberOf;
	}

	public String getWhenCreated() {
		return whenCreated;
	}

	public void setWhenCreated(String whenCreated) {
		this.whenCreated = whenCreated;
	}

	@Override
	public String toString() {
		return "Person [dn=" + dn + ", cn=" + cn + ", sn=" + sn + ", whenCreated=" + whenCreated
				+ ", objectclass=" + objectclass + ", telephoneNumber="
				+ telephoneNumber + ", sAMAccountName=" + sAMAccountName + ", name=" + name + ", mail=" + mail
				+ ", givenName=" + givenName + ", description=" + description + ", displayName=" + displayName
				+ ", distinguishedName=" + distinguishedName + ", userAccountControl=" + userAccountControl
				+ ", userPrincipalName=" + userPrincipalName + ", memberOf=" + memberOf + "]";
	}

	
}

直接写个REST测试:

package com.test.rest;

import static org.springframework.ldap.query.LdapQueryBuilder.query;

import java.util.List;

import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.query.LdapQuery;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.test.domain.Person;
import com.test.repository.PersonRepo;




@RestController
@RequestMapping("/admin")
public class LdapController {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(LdapController.class);
	
	@Autowired
	private PersonRepo personRepo;
	
	@Autowired
	private LdapTemplate ldapTemplate;
	
	@Value("${ldap.searchBaseDn}")
    public String BaseDn;
	
	@RequestMapping("/test1")
	public String findOne(@RequestParam(value = "username", defaultValue = "test9") String username){
        
		LdapQuery query = query()
				.where("cn").is(username);
	  			//.base("ou=maksad")	
	  			//.attributes("cn", "sn") 
	  			/*.where("objectclass").is("person")
	  			.and("sn").is("朱");*/

		Person person = ldapTemplate.findOne(query, Person.class);
		System.out.println(person.toString());
		
		
        return "ok";
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值