阅读 63

SpringBoot Security整合JWT授权RestAPI

本教程主要详细讲解SpringBoot Security整合JWT授权RestAPI。

基础环境


技术版本
Java1.8+
SpringBoot2.x.x
Security5.x
JWT0.9.0

创建项目


  • 初始化项目

mvn archetype: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的支持

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">     <parent>         <artifactId>spring-learn-integration-security</artifactId>         <groupId>com.edurt.sli</groupId>         <version>1.0.0</version>     </parent>     <modelVersion>4.0.0</modelVersion>     <artifactId>spring-learn-integration-security-jwt</artifactId>     <name>SpringBoot Security整合JWT授权RestAPI</name>     <properties>         <system.java.version>1.8</system.java.version>         <plugin.maven.compiler.version>3.3</plugin.maven.compiler.version>         <dependency.springboot2.common.version>2.0.3.RELEASE</dependency.springboot2.common.version>         <dependency.lombok.version>1.18.6</dependency.lombok.version>         <dependency.jwt.version>0.9.0</dependency.jwt.version>         <dependency.jackson.version>2.9.9</dependency.jackson.version>     </properties>     <dependencies>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>             <version>${dependency.springboot2.common.version}</version>         </dependency>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-security</artifactId>             <version>${dependency.springboot2.common.version}</version>         </dependency>         <dependency>             <groupId>io.jsonwebtoken</groupId>             <artifactId>jjwt</artifactId>             <version>${dependency.jwt.version}</version>         </dependency>         <dependency>             <groupId>org.projectlombok</groupId>             <artifactId>lombok</artifactId>             <version>${dependency.lombok.version}</version>         </dependency>         <dependency>             <groupId>com.fasterxml.jackson.core</groupId>             <artifactId>jackson-databind</artifactId>             <version>${dependency.jackson.version}</version>         </dependency>     </dependencies>     <build>         <plugins>             <plugin>                 <groupId>org.springframework.boot</groupId>                 <artifactId>spring-boot-maven-plugin</artifactId>                 <version>${dependency.springboot2.common.version}</version>                 <configuration>                     <fork>true</fork>                 </configuration>             </plugin>             <plugin>                 <groupId>org.apache.maven.plugins</groupId>                 <artifactId>maven-compiler-plugin</artifactId>                 <version>${plugin.maven.compiler.version}</version>                 <configuration>                     <source>${system.java.version}</source>                     <target>${system.java.version}</target>                 </configuration>             </plugin>         </plugins>     </build> </project> 复制代码

spring-boot-starter-security启动spring security安全框架 jjwt启动spring security jwt框架支持

  • 一个简单的应用类

/**  * Licensed to the Apache Software Foundation (ASF) under one  * or more contributor license agreements.  See the NOTICE file  * distributed with this work for additional information  * regarding copyright ownership.  The ASF licenses this file  * to you under the Apache License, Version 2.0 (the  * "License"); you may not use this file except in compliance  * with the License.  You may obtain a copy of the License at  * <p>  * http://www.apache.org/licenses/LICENSE-2.0  * <p>  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package com.edurt.sli.slisj; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.stereotype.Component; /**  * <p> SpringBootSecurityJwtIntegration </p>  * <p> Description : SpringBootSecurityJwtIntegration </p>  * <p> Author : qianmoQ </p>  * <p> Version : 1.0 </p>  * <p> Create Time : 2019-11-26 20:45 </p>  * <p> Author Email: <a href="mailTo:shichengoooo@163.com">qianmoQ</a> </p>  */ @SpringBootApplication @Component(value = "com.edurt.sli.slisj") public class SpringBootSecurityJwtIntegration {     public static void main(String[] args) {         SpringApplication.run(SpringBootSecurityJwtIntegration.class, args);     }      } 复制代码

配置 JWT


  • /src/main/java/com/edurt/sli/slisj目录下创建config目录,并在该目录下新建jwt目录,在该目录下新建JwtTokenTemplate工具模板

/**  * Licensed to the Apache Software Foundation (ASF) under one  * or more contributor license agreements.  See the NOTICE file  * distributed with this work for additional information  * regarding copyright ownership.  The ASF licenses this file  * to you under the Apache License, Version 2.0 (the  * "License"); you may not use this file except in compliance  * with the License.  You may obtain a copy of the License at  * <p>  * http://www.apache.org/licenses/LICENSE-2.0  * <p>  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package com.edurt.sli.slisj.config.jwt; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import java.io.Serializable; import java.time.Instant; import java.util.Date; import java.util.HashMap; import java.util.Map; /**  * <p> JwtTokenTemplate </p>  * <p> Description : JwtTokenTemplate </p>  * <p> Author : qianmoQ </p>  * <p> Version : 1.0 </p>  * <p> Create Time : 2019-11-26 20:49 </p>  * <p> Author Email: <a href="mailTo:shichengoooo@163.com">qianmoQ</a> </p>  */ @Component public class JwtTokenTemplate implements Serializable {     private static final String CLAIM_KEY_USERNAME = "sub";     private static final long EXPIRATION_TIME = 432000000;     private static final String SECRET = "secret";     public String generateToken(UserDetails userDetails) {         Map<String, Object> claims = new HashMap<>(16);         claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());         return Jwts.builder()                 .setClaims(claims)                 .setExpiration(new Date(Instant.now().toEpochMilli() + EXPIRATION_TIME))                 .signWith(SignatureAlgorithm.HS512, SECRET)                 .compact();     }     public Boolean validateToken(String token, UserDetails userDetails) {         User user = (User) userDetails;         String username = getUsernameFromToken(token);         return (username.equals(user.getUsername()) && !isTokenExpired(token));     }     public Boolean isTokenExpired(String token) {         Date expiration = getExpirationDateFromToken(token);         return expiration.before(new Date());     }     public String getUsernameFromToken(String token) {         String username = getClaimsFromToken(token).getSubject();         return username;     }     public Date getExpirationDateFromToken(String token) {         Date expiration = getClaimsFromToken(token).getExpiration();         return expiration;     }     private Claims getClaimsFromToken(String token) {         Claims claims = Jwts.parser()                 .setSigningKey(SECRET)                 .parseClaimsJws(token)                 .getBody();         return claims;     } } 复制代码

  • jwt该目录下新建JwtTokenFilter过滤器

/**  * Licensed to the Apache Software Foundation (ASF) under one  * or more contributor license agreements.  See the NOTICE file  * distributed with this work for additional information  * regarding copyright ownership.  The ASF licenses this file  * to you under the Apache License, Version 2.0 (the  * "License"); you may not use this file except in compliance  * with the License.  You may obtain a copy of the License at  * <p>  * http://www.apache.org/licenses/LICENSE-2.0  * <p>  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package com.edurt.sli.slisj.config.jwt; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /**  * <p> JwtTokenFilter </p>  * <p> Description : JwtTokenFilter </p>  * <p> Author : qianmoQ </p>  * <p> Version : 1.0 </p>  * <p> Create Time : 2019-11-26 20:49 </p>  * <p> Author Email: <a href="mailTo:shichengoooo@163.com">qianmoQ</a> </p>  */ @Component public class JwtTokenFilter extends OncePerRequestFilter {     public static final String HEADER_STRING = "Authorization";     @Autowired     private UserDetailsService userDetailsService;     @Autowired     private JwtTokenTemplate jwtTokenTemplate;     @Override     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {         String token = request.getHeader(HEADER_STRING);         if (null != token) {             String username = jwtTokenTemplate.getUsernameFromToken(token);             if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {                 UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);                 if (jwtTokenTemplate.validateToken(token, userDetails)) {                     UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(                             userDetails, null, userDetails.getAuthorities());                     authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(                             request));                     SecurityContextHolder.getContext().setAuthentication(authentication);                 }             }         }         chain.doFilter(request, response);     } } 复制代码

配置Security


  • config目录下新建JwtSecurityConfig文件

/**  * Licensed to the Apache Software Foundation (ASF) under one  * or more contributor license agreements.  See the NOTICE file  * distributed with this work for additional information  * regarding copyright ownership.  The ASF licenses this file  * to you under the Apache License, Version 2.0 (the  * "License"); you may not use this file except in compliance  * with the License.  You may obtain a copy of the License at  * <p>  * http://www.apache.org/licenses/LICENSE-2.0  * <p>  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package com.edurt.sli.slisj.config; import com.edurt.sli.slisj.config.jwt.JwtTokenFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; 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.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /**  * <p> JwtSecurityConfig </p>  * <p> Description : JwtSecurityConfig </p>  * <p> Author : qianmoQ </p>  * <p> Version : 1.0 </p>  * <p> Create Time : 2019-11-26 20:46 </p>  * <p> Author Email: <a href="mailTo:shichengoooo@163.com">qianmoQ</a> </p>  */ @Configuration @EnableWebSecurity public class JwtSecurityConfig extends WebSecurityConfigurerAdapter {     @Autowired     private UserDetailsService userDetailsService;     @Autowired     public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {         auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());     }     @Bean     public PasswordEncoder passwordEncoder() {         return new BCryptPasswordEncoder();     }     @Override     protected void configure(HttpSecurity http) throws Exception {         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     public JwtTokenFilter authenticationTokenFilterBean() {         return new JwtTokenFilter();     }     @Bean     @Override     public AuthenticationManager authenticationManagerBean() throws Exception {         return super.authenticationManagerBean();     } } 复制代码

  • config目录下新建JwtUserDetailsService文件

/**  * Licensed to the Apache Software Foundation (ASF) under one  * or more contributor license agreements.  See the NOTICE file  * distributed with this work for additional information  * regarding copyright ownership.  The ASF licenses this file  * to you under the Apache License, Version 2.0 (the  * "License"); you may not use this file except in compliance  * with the License.  You may obtain a copy of the License at  * <p>  * http://www.apache.org/licenses/LICENSE-2.0  * <p>  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package com.edurt.sli.slisj.config; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.ArrayList; /**  * <p> JwtUserDetailsService </p>  * <p> Description : JwtUserDetailsService </p>  * <p> Author : qianmoQ </p>  * <p> Version : 1.0 </p>  * <p> Create Time : 2019-11-26 20:54 </p>  * <p> Author Email: <a href="mailTo:shichengoooo@163.com">qianmoQ</a> </p>  */ @Service public class JwtUserDetailsService implements UserDetailsService {     @Override     public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {         if (userName.equals("admin")) {             return new User("admin", "$2a$10$slYQmyNdGzTn7ZLBXBChFOC9f6kFjAqPhccnP6DxlWXx2lPk1C3G6",                     new ArrayList<>());         }         return null;     } } 复制代码

  • 在resources资源目录下创建一个application.properties的配置文件,内容如下

server.port=8989 复制代码

创建授权参数


/src/main/java/com/edurt/sli/slisj目录下创建param目录,并在该目录下新建JwtParam文件

/**  * Licensed to the Apache Software Foundation (ASF) under one  * or more contributor license agreements.  See the NOTICE file  * distributed with this work for additional information  * regarding copyright ownership.  The ASF licenses this file  * to you under the Apache License, Version 2.0 (the  * "License"); you may not use this file except in compliance  * with the License.  You may obtain a copy of the License at  * <p>  * http://www.apache.org/licenses/LICENSE-2.0  * <p>  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package com.edurt.sli.slisj.param; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; /**  * <p> JwtParam </p>  * <p> Description : JwtParam </p>  * <p> Author : qianmoQ </p>  * <p> Version : 1.0 </p>  * <p> Create Time : 2019-11-26 20:59 </p>  * <p> Author Email: <a href="mailTo:shichengoooo@163.com">qianmoQ</a> </p>  */ @Data @ToString @AllArgsConstructor @NoArgsConstructor public class JwtParam {     private String username;     private String password; } 复制代码

创建授权接口


/src/main/java/com/edurt/sli/slisj目录下创建controller目录,并在该目录下新建HelloJwtController文件

/**  * Licensed to the Apache Software Foundation (ASF) under one  * or more contributor license agreements.  See the NOTICE file  * distributed with this work for additional information  * regarding copyright ownership.  The ASF licenses this file  * to you under the Apache License, Version 2.0 (the  * "License"); you may not use this file except in compliance  * with the License.  You may obtain a copy of the License at  * <p>  * http://www.apache.org/licenses/LICENSE-2.0  * <p>  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package com.edurt.sli.slisj.controller; import com.edurt.sli.slisj.config.JwtUserDetailsService; import com.edurt.sli.slisj.config.jwt.JwtTokenTemplate; import com.edurt.sli.slisj.param.JwtParam; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.*; /**  * <p> HelloJwtController </p>  * <p> Description : HelloJwtController </p>  * <p> Author : qianmoQ </p>  * <p> Version : 1.0 </p>  * <p> Create Time : 2019-11-26 20:58 </p>  * <p> Author Email: <a href="mailTo:shichengoooo@163.com">qianmoQ</a> </p>  */ @RestController @RequestMapping(value = "auth") public class HelloJwtController {     @Autowired     private JwtTokenTemplate jwtTokenTemplate;     @Autowired     private AuthenticationManager authenticationManager;     @Autowired     private JwtUserDetailsService userDetailsService;     @PostMapping(value = "login")     public String login(@RequestBody JwtParam body) throws AuthenticationException {         UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(body.getUsername(), body.getPassword());         Authentication authentication = authenticationManager.authenticate(authenticationToken);         SecurityContextHolder.getContext().setAuthentication(authentication);         UserDetails userDetails = userDetailsService.loadUserByUsername(body.getUsername());         return jwtTokenTemplate.generateToken(userDetails);     }     @GetMapping(value = "hello")     public String hello() {         return "Hello Jwt!!!";     } } 复制代码

校验授权


  • 在控制台输入以下命令(未授权时)

curl -X GET 'http://localhost:8989/auth/hello' 复制代码

会出现以下错误信息

{     "timestamp": "2019-11-26T13:05:05.204+0000",     "status": 403,     "error": "Forbidden",     "message": "Access Denied",     "path": "/auth/hello" } 复制代码

  • 提示我们未授权,这时我们使用/auth/login去获得授权的token

curl -X POST '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 -X GET 'http://127.0.0.1:8989/auth/hello' --header 'Authorization: eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTU3NTIwNTg4OH0.zc3JTsIHIZSmi-hrgCB1AKrrjVWtnWB4YJjOhzml2k9qRdTGdoDYKM1XriQIAInvIrTDDkpozT4Ny58Wcpm4JA' 复制代码

返回以下信息

Hello Jwt!!! 复制代码

此时我们已经完成JWT授权配置

打包文件部署


  • 打包数据

mvn clean package -Dmaven.test.skip=true -X 复制代码

运行打包后的文件即可

java -jar target/spring-learn-integration-security-jwt-1.0.0.jar


作者:EdurtIO
链接:https://juejin.cn/post/7171982443803590692


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐