SpringBoot Security整合JWT授权RestAPI的实现
本教程主要详细讲解SpringBootSecurity整合JWT授权RestAPI。
基础环境
技术 | 版本 |
---|---|
Java | 1.8+ |
SpringBoot | 2.x.x |
Security | 5.x |
JWT | 0.9.0 |
创建项目
初始化项目
mvnarchetype:generate-DgroupId=com.edurt.sli.slisj-DartifactId=spring-learn-integration-security-jwt-DarchetypeArtifactId=maven-archetype-quickstart-Dversion=1.0.0-DinteractiveMode=false
修改pom.xml增加security和jwt的支持
spring-learn-integration-security com.edurt.sli 1.0.0 4.0.0 spring-learn-integration-security-jwt SpringBootSecurity整合JWT授权RestAPI 1.8 3.3 2.0.3.RELEASE 1.18.6 0.9.0 2.9.9 org.springframework.boot spring-boot-starter-web ${dependency.springboot2.common.version} org.springframework.boot spring-boot-starter-security ${dependency.springboot2.common.version} io.jsonwebtoken jjwt ${dependency.jwt.version} org.projectlombok lombok ${dependency.lombok.version} com.fasterxml.jackson.core jackson-databind ${dependency.jackson.version} org.springframework.boot spring-boot-maven-plugin ${dependency.springboot2.common.version} true org.apache.maven.plugins maven-compiler-plugin ${plugin.maven.compiler.version} ${system.java.version}
spring-boot-starter-security启动springsecurity安全框架
jjwt启动springsecurityjwt框架支持
一个简单的应用类
/** *LicensedtotheApacheSoftwareFoundation(ASF)underone *ormorecontributorlicenseagreements.SeetheNOTICEfile *distributedwiththisworkforadditionalinformation *regardingcopyrightownership.TheASFlicensesthisfile *toyouundertheApacheLicense,Version2.0(the *"License");youmaynotusethisfileexceptincompliance *withtheLicense.YoumayobtainacopyoftheLicenseat **http://www.apache.org/licenses/LICENSE-2.0 *
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense. */ packagecom.edurt.sli.slisj; importorg.springframework.boot.SpringApplication; importorg.springframework.boot.autoconfigure.SpringBootApplication; importorg.springframework.stereotype.Component; /** *
SpringBootSecurityJwtIntegration
*Description:SpringBootSecurityJwtIntegration
*Author:qianmoQ
*Version:1.0
*CreateTime:2019-11-2620:45
*AuthorEmail:
*/ @SpringBootApplication @Component(value="com.edurt.sli.slisj") publicclassSpringBootSecurityJwtIntegration{ publicstaticvoidmain(String[]args){ SpringApplication.run(SpringBootSecurityJwtIntegration.class,args); } }qianmoQ
配置JWT
在/src/main/java/com/edurt/sli/slisj目录下创建config目录,并在该目录下新建jwt目录,在该目录下新建JwtTokenTemplate工具模板
/** *LicensedtotheApacheSoftwareFoundation(ASF)underone *ormorecontributorlicenseagreements.SeetheNOTICEfile *distributedwiththisworkforadditionalinformation *regardingcopyrightownership.TheASFlicensesthisfile *toyouundertheApacheLicense,Version2.0(the *"License");youmaynotusethisfileexceptincompliance *withtheLicense.YoumayobtainacopyoftheLicenseat **http://www.apache.org/licenses/LICENSE-2.0 *
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense. */ packagecom.edurt.sli.slisj.config.jwt; importio.jsonwebtoken.Claims; importio.jsonwebtoken.Jwts; importio.jsonwebtoken.SignatureAlgorithm; importorg.springframework.security.core.userdetails.User; importorg.springframework.security.core.userdetails.UserDetails; importorg.springframework.stereotype.Component; importjava.io.Serializable; importjava.time.Instant; importjava.util.Date; importjava.util.HashMap; importjava.util.Map; /** *
JwtTokenTemplate
*Description:JwtTokenTemplate
*Author:qianmoQ
*Version:1.0
*CreateTime:2019-11-2620:49
*AuthorEmail:
*/ @Component publicclassJwtTokenTemplateimplementsSerializable{ privatestaticfinalStringCLAIM_KEY_USERNAME="sub"; privatestaticfinallongEXPIRATION_TIME=432000000; privatestaticfinalStringSECRET="secret"; publicStringgenerateToken(UserDetailsuserDetails){ MapqianmoQ claims=newHashMap<>(16); claims.put(CLAIM_KEY_USERNAME,userDetails.getUsername()); returnJwts.builder() .setClaims(claims) .setExpiration(newDate(Instant.now().toEpochMilli()+EXPIRATION_TIME)) .signWith(SignatureAlgorithm.HS512,SECRET) .compact(); } publicBooleanvalidateToken(Stringtoken,UserDetailsuserDetails){ Useruser=(User)userDetails; Stringusername=getUsernameFromToken(token); return(username.equals(user.getUsername())&&!isTokenExpired(token)); } publicBooleanisTokenExpired(Stringtoken){ Dateexpiration=getExpirationDateFromToken(token); returnexpiration.before(newDate()); } publicStringgetUsernameFromToken(Stringtoken){ Stringusername=getClaimsFromToken(token).getSubject(); returnusername; } publicDategetExpirationDateFromToken(Stringtoken){ Dateexpiration=getClaimsFromToken(token).getExpiration(); returnexpiration; } privateClaimsgetClaimsFromToken(Stringtoken){ Claimsclaims=Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token) .getBody(); returnclaims; } }
在jwt该目录下新建JwtTokenFilter过滤器
/** *LicensedtotheApacheSoftwareFoundation(ASF)underone *ormorecontributorlicenseagreements.SeetheNOTICEfile *distributedwiththisworkforadditionalinformation *regardingcopyrightownership.TheASFlicensesthisfile *toyouundertheApacheLicense,Version2.0(the *"License");youmaynotusethisfileexceptincompliance *withtheLicense.YoumayobtainacopyoftheLicenseat **http://www.apache.org/licenses/LICENSE-2.0 *
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense. */ packagecom.edurt.sli.slisj.config.jwt; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken; importorg.springframework.security.core.context.SecurityContextHolder; importorg.springframework.security.core.userdetails.UserDetails; importorg.springframework.security.core.userdetails.UserDetailsService; importorg.springframework.security.web.authentication.WebAuthenticationDetailsSource; importorg.springframework.stereotype.Component; importorg.springframework.web.filter.OncePerRequestFilter; importjavax.servlet.FilterChain; importjavax.servlet.ServletException; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.io.IOException; /** *
JwtTokenFilter
*Description:JwtTokenFilter
*Author:qianmoQ
*Version:1.0
*CreateTime:2019-11-2620:49
*AuthorEmail:
*/ @Component publicclassJwtTokenFilterextendsOncePerRequestFilter{ publicstaticfinalStringHEADER_STRING="Authorization"; @Autowired privateUserDetailsServiceuserDetailsService; @Autowired privateJwtTokenTemplatejwtTokenTemplate; @Override protectedvoiddoFilterInternal(HttpServletRequestrequest,HttpServletResponseresponse,FilterChainchain)throwsServletException,IOException{ Stringtoken=request.getHeader(HEADER_STRING); if(null!=token){ Stringusername=jwtTokenTemplate.getUsernameFromToken(token); if(username!=null&&SecurityContextHolder.getContext().getAuthentication()==null){ UserDetailsuserDetails=this.userDetailsService.loadUserByUsername(username); if(jwtTokenTemplate.validateToken(token,userDetails)){ UsernamePasswordAuthenticationTokenauthentication=newUsernamePasswordAuthenticationToken( userDetails,null,userDetails.getAuthorities()); authentication.setDetails(newWebAuthenticationDetailsSource().buildDetails( request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } } chain.doFilter(request,response); } }qianmoQ
配置Security
在config目录下新建JwtSecurityConfig文件
/** *LicensedtotheApacheSoftwareFoundation(ASF)underone *ormorecontributorlicenseagreements.SeetheNOTICEfile *distributedwiththisworkforadditionalinformation *regardingcopyrightownership.TheASFlicensesthisfile *toyouundertheApacheLicense,Version2.0(the *"License");youmaynotusethisfileexceptincompliance *withtheLicense.YoumayobtainacopyoftheLicenseat **http://www.apache.org/licenses/LICENSE-2.0 *
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense. */ packagecom.edurt.sli.slisj.config; importcom.edurt.sli.slisj.config.jwt.JwtTokenFilter; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.http.HttpMethod; importorg.springframework.security.authentication.AuthenticationManager; importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; importorg.springframework.security.config.annotation.web.builders.HttpSecurity; importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity; importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; importorg.springframework.security.config.http.SessionCreationPolicy; importorg.springframework.security.core.userdetails.UserDetailsService; importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; importorg.springframework.security.crypto.password.PasswordEncoder; importorg.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /** *
JwtSecurityConfig
*Description:JwtSecurityConfig
*Author:qianmoQ
*Version:1.0
*CreateTime:2019-11-2620:46
*AuthorEmail:
*/ @Configuration @EnableWebSecurity publicclassJwtSecurityConfigextendsWebSecurityConfigurerAdapter{ @Autowired privateUserDetailsServiceuserDetailsService; @Autowired publicvoidconfigureGlobal(AuthenticationManagerBuilderauth)throwsException{ auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean publicPasswordEncoderpasswordEncoder(){ returnnewBCryptPasswordEncoder(); } @Override protectedvoidconfigure(HttpSecurityhttp)throwsException{ http.csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .authorizeRequests() .antMatchers(HttpMethod.OPTIONS,"/**").permitAll() .antMatchers("/auth/login").permitAll() .anyRequest().authenticated(); http.addFilterBefore(authenticationTokenFilterBean(),UsernamePasswordAuthenticationFilter.class); http.headers().cacheControl(); } @Bean publicJwtTokenFilterauthenticationTokenFilterBean(){ returnnewJwtTokenFilter(); } @Bean @Override publicAuthenticationManagerauthenticationManagerBean()throwsException{ returnsuper.authenticationManagerBean(); } }qianmoQ
在config目录下新建JwtUserDetailsService文件
/** *LicensedtotheApacheSoftwareFoundation(ASF)underone *ormorecontributorlicenseagreements.SeetheNOTICEfile *distributedwiththisworkforadditionalinformation *regardingcopyrightownership.TheASFlicensesthisfile *toyouundertheApacheLicense,Version2.0(the *"License");youmaynotusethisfileexceptincompliance *withtheLicense.YoumayobtainacopyoftheLicenseat **http://www.apache.org/licenses/LICENSE-2.0 *
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense. */ packagecom.edurt.sli.slisj.config; importorg.springframework.security.core.userdetails.User; importorg.springframework.security.core.userdetails.UserDetails; importorg.springframework.security.core.userdetails.UserDetailsService; importorg.springframework.security.core.userdetails.UsernameNotFoundException; importorg.springframework.stereotype.Service; importjava.util.ArrayList; /** *
JwtUserDetailsService
*Description:JwtUserDetailsService
*Author:qianmoQ
*Version:1.0
*CreateTime:2019-11-2620:54
*AuthorEmail:
*/ @Service publicclassJwtUserDetailsServiceimplementsUserDetailsService{ @Override publicUserDetailsloadUserByUsername(StringuserName)throwsUsernameNotFoundException{ if(userName.equals("admin")){ returnnewUser("admin","$2a$10$slYQmyNdGzTn7ZLBXBChFOC9f6kFjAqPhccnP6DxlWXx2lPk1C3G6", newArrayList<>()); } returnnull; } }qianmoQ
在resources资源目录下创建一个application.properties的配置文件,内容如下
server.port=8989
创建授权参数
在/src/main/java/com/edurt/sli/slisj目录下创建param目录,并在该目录下新建JwtParam文件
/** *LicensedtotheApacheSoftwareFoundation(ASF)underone *ormorecontributorlicenseagreements.SeetheNOTICEfile *distributedwiththisworkforadditionalinformation *regardingcopyrightownership.TheASFlicensesthisfile *toyouundertheApacheLicense,Version2.0(the *"License");youmaynotusethisfileexceptincompliance *withtheLicense.YoumayobtainacopyoftheLicenseat **http://www.apache.org/licenses/LICENSE-2.0 *
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense. */ packagecom.edurt.sli.slisj.param; importlombok.AllArgsConstructor; importlombok.Data; importlombok.NoArgsConstructor; importlombok.ToString; /** *
JwtParam
*Description:JwtParam
*Author:qianmoQ
*Version:1.0
*CreateTime:2019-11-2620:59
*AuthorEmail:
*/ @Data @ToString @AllArgsConstructor @NoArgsConstructor publicclassJwtParam{ privateStringusername; privateStringpassword; }qianmoQ
创建授权接口
在/src/main/java/com/edurt/sli/slisj目录下创建controller目录,并在该目录下新建HelloJwtController文件
/** *LicensedtotheApacheSoftwareFoundation(ASF)underone *ormorecontributorlicenseagreements.SeetheNOTICEfile *distributedwiththisworkforadditionalinformation *regardingcopyrightownership.TheASFlicensesthisfile *toyouundertheApacheLicense,Version2.0(the *"License");youmaynotusethisfileexceptincompliance *withtheLicense.YoumayobtainacopyoftheLicenseat **http://www.apache.org/licenses/LICENSE-2.0 *
*Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense. */ packagecom.edurt.sli.slisj.controller; importcom.edurt.sli.slisj.config.JwtUserDetailsService; importcom.edurt.sli.slisj.config.jwt.JwtTokenTemplate; importcom.edurt.sli.slisj.param.JwtParam; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.security.authentication.AuthenticationManager; importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken; importorg.springframework.security.core.Authentication; importorg.springframework.security.core.AuthenticationException; importorg.springframework.security.core.context.SecurityContextHolder; importorg.springframework.security.core.userdetails.UserDetails; importorg.springframework.web.bind.annotation.*; /** *
HelloJwtController
*Description:HelloJwtController
*Author:qianmoQ
*Version:1.0
*CreateTime:2019-11-2620:58
*AuthorEmail:
*/ @RestController @RequestMapping(value="auth") publicclassHelloJwtController{ @Autowired privateJwtTokenTemplatejwtTokenTemplate; @Autowired privateAuthenticationManagerauthenticationManager; @Autowired privateJwtUserDetailsServiceuserDetailsService; @PostMapping(value="login") publicStringlogin(@RequestBodyJwtParambody)throwsAuthenticationException{ UsernamePasswordAuthenticationTokenauthenticationToken=newUsernamePasswordAuthenticationToken(body.getUsername(),body.getPassword()); Authenticationauthentication=authenticationManager.authenticate(authenticationToken); SecurityContextHolder.getContext().setAuthentication(authentication); UserDetailsuserDetails=userDetailsService.loadUserByUsername(body.getUsername()); returnjwtTokenTemplate.generateToken(userDetails); } @GetMapping(value="hello") publicStringhello(){ return"HelloJwt!!!"; } }qianmoQ
校验授权
在控制台输入以下命令(未授权时)
curl-XGET'http://localhost:8989/auth/hello'
会出现以下错误信息
{ "timestamp":"2019-11-26T13:05:05.204+0000", "status":403, "error":"Forbidden", "message":"AccessDenied", "path":"/auth/hello" }
提示我们未授权,这时我们使用/auth/login去获得授权的token
curl-XPOST'http://127.0.0.1:8989/auth/login'--header'Content-Type:application/json'-d'{"username":"admin","password":"password"}'
返回以下token信息
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTU3NTIwNTg4OH0.zc3JTsIHIZSmi-hrgCB1AKrrjVWtnWB4YJjOhzml2k9qRdTGdoDYKM1XriQIAInvIrTDDkpozT4Ny58Wcpm4JA
这时我们使用返回的token进行访问/auth/hello接口获取数据
curl-XGET'http://127.0.0.1:8989/auth/hello'--header'Authorization:eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTU3NTIwNTg4OH0.zc3JTsIHIZSmi-hrgCB1AKrrjVWtnWB4YJjOhzml2k9qRdTGdoDYKM1XriQIAInvIrTDDkpozT4Ny58Wcpm4JA'
返回以下信息
HelloJwt!!!
此时我们已经完成JWT授权配置
打包文件部署
打包数据
mvncleanpackage-Dmaven.test.skip=true-X
运行打包后的文件即可
java-jartarget/spring-learn-integration-security-jwt-1.0.0.jar
源码地址
- GitHub
- Gitee
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。