Vue+Jwt+SpringBoot+Ldap完成登录认证的示例代码(3)

2.2应用配置文件

#Logging_config
logging.level.root=INFO
logging.level.org.springframework.web=WARN
logging.file=minibox.log

#server_config
#使用了SSL,并且在ldap配置中使用了ldaps,这里同时也需要把AD的证书导入到server.keystore中。具体的可以查看java的keytool工具
server.port=8443
server.ssl.key-store=classpath:server.keystore
server.ssl.key-store-password=minibox
server.ssl.key-password=minibox

#jwt
#jwt加解密时使用的key
jwt.key=minibox

#ldap_config
#ldap配置信息,注意这里的userDn一定要写这种形式。referral设置为follow,说不清用途,似乎只有连接AD时才需要配置
ldap.url=ldaps://192.168.227.128:636
ldap.base=ou=Employees,dc=minibox,dc=com
ldap.userDn=cn=Administrator,cn=Users,dc=minibox,dc=com
ldap.userPwd=qqq111!!!!
ldap.referral=follow
ldap.domainName=@minibox.com

3.Spring主配置类

package an;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
@SpringBootApplication//相当于@Configuration,@EnableAutoConfiguration,@ComponentScan
public class Application {

  /*
  * SpringLdap配置。通过@Value注解读取之前配置文件中的值
  */
  @Value("${ldap.url}")
  private String ldapUrl;

  @Value("${ldap.base}")
  private String ldapBase;

  @Value("${ldap.userDn}")
  private String ldapUserDn;

  @Value("${ldap.userPwd}")
  private String ldapUserPwd;

  @Value("${ldap.referral}")
  private String ldapReferral;

  /*
  *SpringLdap的javaConfig注入方式
  */
  @Bean
  public LdapTemplate ldapTemplate() {
    return new LdapTemplate(contextSourceTarget());
  }

  @Bean
  public LdapContextSource contextSourceTarget() {
    LdapContextSource ldapContextSource = new LdapContextSource();
    ldapContextSource.setUrl(ldapUrl);
    ldapContextSource.setBase(ldapBase);
    ldapContextSource.setUserDn(ldapUserDn);
    ldapContextSource.setPassword(ldapUserPwd);
    ldapContextSource.setReferral(ldapReferral);
    return ldapContextSource;
  }

  public static void main(String[] args) throws Exception {
    SpringApplication.run(Application.class, args);
  }
}

3.1提供认证服务的类

package an.auth;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ldap.NamingException;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import static org.springframework.ldap.query.LdapQueryBuilder.query;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import an.entity.Employee;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
@RestController
@RequestMapping("/auth")
public class JwtAuth {

  //jwt加密密匙
  @Value("${jwt.key}")
  private String jwtKey;

  //域名后缀
  @Value("${ldap.domainName}")
  private String ldapDomainName;

  //ldap模板
  @Autowired
  private LdapTemplate ldapTemplate;

  /**
   * 将域用户属性通过EmployeeAttributesMapper填充到Employee类中,返回一个填充信息的Employee实例
   */
  private class EmployeeAttributesMapper implements AttributesMapper<Employee> {
    public Employee mapFromAttributes(Attributes attrs) throws NamingException, javax.naming.NamingException {
      Employee employee = new Employee();
      employee.setName((String) attrs.get("sAMAccountName").get());
      employee.setDisplayName((String) attrs.get("displayName").get());
      employee.setRole((String) attrs.get("memberOf").toString());
      return employee;
    }
  }

  /**
   * @param username 用户提交的名称
   * @param password 用户提交的密码
   * @return 成功返回加密后的token信息,失败返回错误HTTP状态码
   */
  @CrossOrigin//因为需要跨域访问,所以要加这个注解
  @RequestMapping(method = RequestMethod.POST)
  public ResponseEntity<String> authByAd(
      @RequestParam(value = "username") String username,
      @RequestParam(value = "password") String password) {
    //这里注意用户名加域名后缀 userDn格式:anwx@minibox.com
    String userDn = username + ldapDomainName;
    //token过期时间 4小时
    Date tokenExpired = new Date(new Date().getTime() + 60*60*4*1000);
    DirContext ctx = null;
    try {
      //使用用户名、密码验证域用户
      ctx = ldapTemplate.getContextSource().getContext(userDn, password);
      //如果验证成功根据sAMAccountName属性查询用户名和用户所属的组
      Employee employee = ldapTemplate                            .search(query().where("objectclass").is("person").and("sAMAccountName").is(username),
              new EmployeeAttributesMapper())
          .get(0);
      //使用Jwt加密用户名和用户所属组信息
      String compactJws = Jwts.builder()
          .setSubject(employee.getName())
          .setAudience(employee.getRole())
          .setExpiration(tokenExpired)
          .signWith(SignatureAlgorithm.HS512, jwtKey).compact();
      //登录成功,返回客户端token信息。这里只加密了用户名和用户角色,而displayName和tokenExpired没有加密
      Map<String, Object> userInfo = new HashMap<String, Object>();
      userInfo.put("token", compactJws);
      userInfo.put("displayName", employee.getDisplayName());
      userInfo.put("tokenExpired", tokenExpired.getTime());
      return new ResponseEntity<String>(JSON.toJSONString(userInfo , SerializerFeature.DisableCircularReferenceDetect) , HttpStatus.OK);
    } catch (Exception e) {
      //登录失败,返回失败HTTP状态码
      return new ResponseEntity<String>(HttpStatus.UNAUTHORIZED);
    } finally {
      //关闭ldap连接
      LdapUtils.closeContext(ctx);
    }
  }

}
      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/106.html