Spring   发布时间:2019-10-07  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Vue+Jwt+SpringBoot+Ldap完成登录认证的示例代码大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

本人野生程序员一名,了解了一些微服务架构、前后端分离、SPA的知识后就想试试做点什么东西。之前一直做后端,前端只是有基础知识。之前学习过angularjs,但当时就是一脸懵逼(完全看不懂是啥)就放弃了。最近又学了Vue,这次感觉总算明白了一些,但其中也跳过很多坑(应该还会更多),在这里写下来记录一下吧。

说回主题,之前传统登录认证的方法基本是由服务器端提供一个登录页面,页面中的一个form输入username和password后POST给服务器,服务器将这些信息与DB或Ldap中的用户信息对比,成功则将这个用户信息记录到session中。

这里我就跳了第一个大坑。传统方式前后端不分离,后端负责页面渲染,但是在前后分离的情况下,后端只负责通过暴露的RestApi提供数据,而页面的渲染、路由都由前端完成。因为rest是无状态的,因此也就不会有session记录到服务器端。

之前一直使用SpringSecurity+Cas+Ldap来做SSO,但是使用Vue做前端后我怎都想不出用之前的方法做SSO(这个坑真的爬了好久才爬出来)。后来终于想明白了上面说的session的问题(我是这么认为的也可能不对,CAS也有RestApi,但是按官网配置没成功,放弃了)。

第一个问题,该如何解决SSO的问题呢,要说到JWT。JWT是个规范,各种语言有各种语言的实现,可以去官网查到。我浅薄的理解是有一个认证服务(你自己写的,Db、Ldap什么都可以)这个认证服务会通过用户的提交信息判断认证是否成功,如果成功则查询出一些用户的信息(用户名、角色什么的),然后JWT把这些信息加密成为一个token,返回给客户端浏览器,浏览器把这些信息存储在localstorage中,以后每次访问资源都会在header中携带这个信息,服务器收到请求后使用和加密时相同的key解密密文,如果解密成功则视为用户已经认证过(当然你可以在加密时添加以一个过期时间)也就完成了SSO。使用解密出的角色信息你就可以判断这个用户是否有权限执行一些业务。这样做完后感觉好像SpringSecurity、Cas在SPA应用中的SSO似乎没什么作用了,目前我是这么认为的(当然可能不对)

第一个问题差不多解决了,来说第二个问题。之前因为有session的存在,在访问受保护的资源时如果服务器端没有当前用户的session,则会强制跳转到登录页。那在前后分离的情况下要如何实现这个需求。思路是这样的:利用Vue-Router的全局路由钩子,在访问任何页面时先判断localStorage中是否存在JWT加密后的token并且token是否过期,如果存在且没有过期则正常跳转到请求的页面,不存在或者过期则跳转到登录页重新认证。

思路说完了,上代码

1.首先你需要一个Ldap,我使用的是AD。这里我建立了一个叫minibox.com的域,并且添加了一个employees的OU,其中有2个子OU,子OU中创建了2个用户。

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

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

2.搭建SpringBoot环境

2.1pom文件

<div class="jb51code">
<pre class="brush:xml;">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:scheR_462_11845@aLOCATIOn="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;

4.0.0 @H_671_41@minibox an@H_607_44@ 0.0.1-SNAPSHOT org.springframework.boot spring-boot-starter-parent@H_607_44@ 1.5.1.RELEASE org.springframework.boot spring-boot-starter-web@H_607_44@ org.springframework.boot spring-boot-starter-test@H_607_44@ test org.springframework.boot spring-boot-starter-hateoas@H_607_44@ org.springframework.boot spring-boot-devtools@H_607_44@ true io.jsonwebtoken jjwt@H_607_44@ 0.7.0 org.springframework.ldap spring-ldap-core@H_607_44@ 2.3.1.RELEASE com.alibaba fastjson@H_607_44@ 1.2.24 org.springframework.boot spring-boot-maven-plugin@H_607_44@ org.springframework.boot spring-boot-maven-plugin@H_607_44@ org.springframework springloaded@H_607_44@ 1.2.0.RELEASE

2.2应用配置文件

l.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=com
ldap.userPwd=qqq111!!!!
ldap.referral=follow
ldap.domainName=@minibox.com

3.Spring主配置类

.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提供认证服务的类

ntext; 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;

/**

/**

  • @param username 用户提交的名称
  • @param password 用户提交的密码
  • @return 成功返回加密后的token信息,失败返回错误http状态码
    /
    @CrossOrigin//因为需要跨域访问,所以要加这个注解
    @requestMapping(method = requestMethod.POST)
    public ResponseEntity 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
    6041000);
    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(JSON.toJSONString(userInfo,serializerFeature.DisableCircularReferenceDetect),httpStatus.OK);
    } catch (Exception E) {
    //登录失败,返回失败http状态码
    return new ResponseEntity(httpStatuS.UNAUTHORIZED);
    } finally {
    //关闭ldap连接
    LdapUtils.closeContext(ctX);
    }
    }

}

4.前端Vue

4.1使用Vue-cli搭建项目,并使用vue-router和vue-resource,不了解的可以搜索下

4.2 main.js

E) has been set in webpack.base.conf with an alias. import Vue from 'vue' import VueRouter from 'vue-router' import Vueresource from 'vue-resource' import store from './store/store' import 'bootstrap/dist/css/bootstrap.css' import App from './App' import Login from './components/login' import Hello from './components/Hello'

Vue.use(VueRouter)
Vue.use(VueresourcE)
//Vue-resource默认以payload方式提交数据,这样设置之后以formData方式提交
Vue.http.options.emulateJSON = true;

const routes = [
{
path: '/login',component : Login
},{
path: '/Hello',component: Hello
}
]

const router = new VueRouter({
routes
})

//默认导航到登录页
router.push('/login')

/
全局路由钩子
访问资源时需要验证localStorage中是否存在token
以及token是否过期
验证成功可以继续跳转
失败返回登录页重新登录
/
router.beforeEach((to,from,next) => {
if(localStorage.token && new Date().getTime() < localStorage.tokenExpired){
next()
}
else{
next('/login')
}
})

new Vue({
el: '#app',template: '',components: { App },router,store
})

4.3 App.vue

4.4 login.vue

BACk"> password" type="password" class="form-control" placeholder="password">
Mary btn-block btn-flat">Sign In

5效果

5.1访问http://localhost:8000时被导航到登录页

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

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

有错误的地方还请各位老师指正。打算把整个分布式系统的开发过程记录下来。

大佬总结

以上是大佬教程为你收集整理的Vue+Jwt+SpringBoot+Ldap完成登录认证的示例代码全部内容,希望文章能够帮你解决Vue+Jwt+SpringBoot+Ldap完成登录认证的示例代码所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签:JwtLdap
猜你在找的Spring相关文章
其他相关热搜词更多
phpJavaPython程序员load如何string使用参数jquery开发安装listlinuxiosandroid工具javascriptcap