From ee5cda000e8a050d22e5eb4996667b298824be92 Mon Sep 17 00:00:00 2001 From: hansonwang99 Date: Tue, 12 Mar 2019 14:53:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E4=BA=8ESpring=20Security=E5=92=8C=20?= =?UTF-8?q?JWT=E8=AE=BE=E8=AE=A1=E4=B8=80=E4=B8=AA=E6=9D=83=E9=99=90?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- springbt_security_jwt/README.md | 1 + springbt_security_jwt/pom.xml | 73 ++++++++++ .../SpringbtSecurityJwtApplication.java | 16 +++ .../springbt_security_jwt/comm/Const.java | 13 ++ .../config/WebSecurityConfig.java | 65 +++++++++ .../controller/JwtAuthController.java | 34 +++++ .../controller/TestController.java | 28 ++++ .../filter/JwtTokenFilter.java | 55 ++++++++ .../model/entity/Role.java | 35 +++++ .../model/entity/User.java | 95 +++++++++++++ .../repository/UserRepository.java | 12 ++ .../service/AuthService.java | 13 ++ .../service/UserService.java | 32 +++++ .../service/impl/AuthServiceImpl.java | 64 +++++++++ .../util/JwtTokenUtil.java | 128 ++++++++++++++++++ .../src/main/resources/application.properties | 12 ++ .../SpringbtSecurityJwtApplicationTests.java | 16 +++ 17 files changed, 692 insertions(+) create mode 100644 springbt_security_jwt/README.md create mode 100644 springbt_security_jwt/pom.xml create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/SpringbtSecurityJwtApplication.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/comm/Const.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/config/WebSecurityConfig.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/controller/JwtAuthController.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/controller/TestController.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/filter/JwtTokenFilter.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/model/entity/Role.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/model/entity/User.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/repository/UserRepository.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/AuthService.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/UserService.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/impl/AuthServiceImpl.java create mode 100644 springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/util/JwtTokenUtil.java create mode 100644 springbt_security_jwt/src/main/resources/application.properties create mode 100644 springbt_security_jwt/src/test/java/cn/codesheep/springbt_security_jwt/SpringbtSecurityJwtApplicationTests.java diff --git a/springbt_security_jwt/README.md b/springbt_security_jwt/README.md new file mode 100644 index 0000000..41f5fff --- /dev/null +++ b/springbt_security_jwt/README.md @@ -0,0 +1 @@ +## SpringBoot + Security + JWT \ No newline at end of file diff --git a/springbt_security_jwt/pom.xml b/springbt_security_jwt/pom.xml new file mode 100644 index 0000000..cee3180 --- /dev/null +++ b/springbt_security_jwt/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + cn.codesheep + springbt_security_jwt + 0.0.1 + jar + + springbt_security_jwt + springbt_security_jwt + + + org.springframework.boot + spring-boot-starter-parent + 2.0.6.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-security + + + + mysql + mysql-connector-java + 5.1.40 + + + + io.jsonwebtoken + jjwt + 0.9.0 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/SpringbtSecurityJwtApplication.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/SpringbtSecurityJwtApplication.java new file mode 100644 index 0000000..7b9b03a --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/SpringbtSecurityJwtApplication.java @@ -0,0 +1,16 @@ +package cn.codesheep.springbt_security_jwt; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @www.codesheep.cn + * 20190312 + */ +@SpringBootApplication +public class SpringbtSecurityJwtApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringbtSecurityJwtApplication.class, args); + } +} diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/comm/Const.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/comm/Const.java new file mode 100644 index 0000000..51ad5c7 --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/comm/Const.java @@ -0,0 +1,13 @@ +package cn.codesheep.springbt_security_jwt.comm; + +/** + * @www.codesheep.cn + * 20190312 + */ +public class Const { + + public static final long EXPIRATION_TIME = 432_000_000; // 5天(以毫秒ms计) + public static final String SECRET = "CodeSheepSecret"; // JWT密码 + public static final String TOKEN_PREFIX = "Bearer"; // Token前缀 + public static final String HEADER_STRING = "Authorization"; // 存放Token的Header Key +} diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/config/WebSecurityConfig.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/config/WebSecurityConfig.java new file mode 100644 index 0000000..c8c0f08 --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/config/WebSecurityConfig.java @@ -0,0 +1,65 @@ +package cn.codesheep.springbt_security_jwt.config; + +import cn.codesheep.springbt_security_jwt.filter.JwtTokenFilter; +import cn.codesheep.springbt_security_jwt.service.UserService; +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.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +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.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +/** + * @www.codesheep.cn + * 20190312 + */ +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled=true) +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + private UserService userService; + + @Bean + public JwtTokenFilter authenticationTokenFilterBean() throws Exception { + return new JwtTokenFilter(); + } + + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Override + protected void configure( AuthenticationManagerBuilder auth ) throws Exception { + auth.userDetailsService( userService ).passwordEncoder( new BCryptPasswordEncoder() ); + } + + @Override + protected void configure( HttpSecurity httpSecurity ) throws Exception { + + httpSecurity.csrf().disable() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() + .authorizeRequests() + .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() + .antMatchers(HttpMethod.POST, "/authentication/**").permitAll() + .antMatchers(HttpMethod.POST).authenticated() + .antMatchers(HttpMethod.PUT).authenticated() + .antMatchers(HttpMethod.DELETE).authenticated() + .antMatchers(HttpMethod.GET).authenticated(); + + httpSecurity + .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class); + httpSecurity.headers().cacheControl(); + } + +} diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/controller/JwtAuthController.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/controller/JwtAuthController.java new file mode 100644 index 0000000..f1dd152 --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/controller/JwtAuthController.java @@ -0,0 +1,34 @@ +package cn.codesheep.springbt_security_jwt.controller; + +import cn.codesheep.springbt_security_jwt.model.entity.User; +import cn.codesheep.springbt_security_jwt.service.AuthService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.AuthenticationException; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * @www.codesheep.cn + * 20190312 + */ +@RestController +public class JwtAuthController { + + @Autowired + private AuthService authService; + + // 登录 + @RequestMapping(value = "/authentication/login", method = RequestMethod.POST) + public String createToken( String username,String password ) throws AuthenticationException { + return authService.login( username, password ); + } + + // 注册 + @RequestMapping(value = "/authentication/register", method = RequestMethod.POST) + public User register( @RequestBody User addedUser ) throws AuthenticationException { + return authService.register(addedUser); + } + +} diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/controller/TestController.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/controller/TestController.java new file mode 100644 index 0000000..1250437 --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/controller/TestController.java @@ -0,0 +1,28 @@ +package cn.codesheep.springbt_security_jwt.controller; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * @www.codesheep.cn + * 20190312 + */ +@RestController +public class TestController { + + // 测试普通权限 + @PreAuthorize("hasAuthority('ROLE_NORMAL')") + @RequestMapping( value="/normal/test", method = RequestMethod.GET ) + public String test1() { + return "ROLE_NORMAL /normal/test接口调用成功!"; + } + + // 测试管理员权限 + @PreAuthorize("hasAuthority('ROLE_ADMIN')") + @RequestMapping( value = "/admin/test", method = RequestMethod.GET ) + public String test2() { + return "ROLE_ADMIN /admin/test接口调用成功!"; + } +} diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/filter/JwtTokenFilter.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/filter/JwtTokenFilter.java new file mode 100644 index 0000000..e4a281f --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/filter/JwtTokenFilter.java @@ -0,0 +1,55 @@ +package cn.codesheep.springbt_security_jwt.filter; + +import cn.codesheep.springbt_security_jwt.comm.Const; +import cn.codesheep.springbt_security_jwt.util.JwtTokenUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +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; + +/** + * @www.codesheep.cn + * 20190312 + */ +@Component +public class JwtTokenFilter extends OncePerRequestFilter { + + @Autowired + private UserDetailsService userDetailsService; + + @Autowired + private JwtTokenUtil jwtTokenUtil; + + @Override + protected void doFilterInternal ( HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + + String authHeader = request.getHeader( Const.HEADER_STRING ); + if (authHeader != null && authHeader.startsWith( Const.TOKEN_PREFIX )) { + final String authToken = authHeader.substring( Const.TOKEN_PREFIX.length() ); + String username = jwtTokenUtil.getUsernameFromToken(authToken); + if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { + UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); + if (jwtTokenUtil.validateToken(authToken, userDetails)) { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails( + request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } + } + chain.doFilter(request, response); + } +} + diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/model/entity/Role.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/model/entity/Role.java new file mode 100644 index 0000000..3e683ad --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/model/entity/Role.java @@ -0,0 +1,35 @@ +package cn.codesheep.springbt_security_jwt.model.entity; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @www.codesheep.cn + * 20190312 + */ +@Entity +public class Role { + + @Id + @GeneratedValue + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/model/entity/User.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/model/entity/User.java new file mode 100644 index 0000000..c194e35 --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/model/entity/User.java @@ -0,0 +1,95 @@ +package cn.codesheep.springbt_security_jwt.model.entity; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * @www.codesheep.cn + * 20190312 + */ +@Entity +public class User implements UserDetails { + + @Id + @GeneratedValue + private Long id; + + private String username; + + private String password; + + @ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER) + private List roles; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public void setUsername(String username) { + this.username = username; + } + + public void setPassword(String password) { + this.password = password; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + // 下面为实现UserDetails而需要的重写方法! + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public Collection getAuthorities() { + List authorities = new ArrayList<>(); + for (Role role : roles) { + authorities.add( new SimpleGrantedAuthority( role.getName() ) ); + } + return authorities; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return password; + } + +} diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/repository/UserRepository.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/repository/UserRepository.java new file mode 100644 index 0000000..318cca9 --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/repository/UserRepository.java @@ -0,0 +1,12 @@ +package cn.codesheep.springbt_security_jwt.repository; + +import cn.codesheep.springbt_security_jwt.model.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * @www.codesheep.cn + * 20190312 + */ +public interface UserRepository extends JpaRepository { + User findByUsername( String username ); +} diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/AuthService.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/AuthService.java new file mode 100644 index 0000000..53f26d4 --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/AuthService.java @@ -0,0 +1,13 @@ +package cn.codesheep.springbt_security_jwt.service; + +import cn.codesheep.springbt_security_jwt.model.entity.User; + +/** + * @www.codesheep.cn + * 20190312 + */ +public interface AuthService { + + User register( User userToAdd ); + String login( String username, String password ); +} diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/UserService.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/UserService.java new file mode 100644 index 0000000..6ccde9f --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/UserService.java @@ -0,0 +1,32 @@ +package cn.codesheep.springbt_security_jwt.service; + +import cn.codesheep.springbt_security_jwt.model.entity.Role; +import cn.codesheep.springbt_security_jwt.model.entity.User; +import cn.codesheep.springbt_security_jwt.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +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; + +/** + * @www.codesheep.cn + * 20190312 + */ +@Service +public class UserService implements UserDetailsService { + + @Autowired + UserRepository userRepository; + + @Override + public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { + + User user = userRepository.findByUsername(s); + if (user == null) { + throw new UsernameNotFoundException("用户不存在"); + } + return user; + } + +} diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/impl/AuthServiceImpl.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/impl/AuthServiceImpl.java new file mode 100644 index 0000000..3354616 --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/service/impl/AuthServiceImpl.java @@ -0,0 +1,64 @@ +package cn.codesheep.springbt_security_jwt.service.impl; + +import cn.codesheep.springbt_security_jwt.comm.Const; +import cn.codesheep.springbt_security_jwt.model.entity.User; +import cn.codesheep.springbt_security_jwt.repository.UserRepository; +import cn.codesheep.springbt_security_jwt.service.AuthService; +import cn.codesheep.springbt_security_jwt.util.JwtTokenUtil; +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.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; + +/** + * @www.codesheep.cn + * 20190312 + */ +@Service +public class AuthServiceImpl implements AuthService { + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private UserDetailsService userDetailsService; + + @Autowired + private JwtTokenUtil jwtTokenUtil; + + @Autowired + private UserRepository userRepository; + + // 登录 + @Override + public String login( String username, String password ) { + + UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken( username, password ); + + final Authentication authentication = authenticationManager.authenticate(upToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + + final UserDetails userDetails = userDetailsService.loadUserByUsername( username ); + final String token = jwtTokenUtil.generateToken(userDetails); + return token; + } + + // 注册 + @Override + public User register( User userToAdd ) { + + final String username = userToAdd.getUsername(); + if( userRepository.findByUsername(username)!=null ) { + return null; + } + BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + final String rawPassword = userToAdd.getPassword(); + userToAdd.setPassword( encoder.encode(rawPassword) ); + return userRepository.save(userToAdd); + } +} diff --git a/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/util/JwtTokenUtil.java b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/util/JwtTokenUtil.java new file mode 100644 index 0000000..fa4e024 --- /dev/null +++ b/springbt_security_jwt/src/main/java/cn/codesheep/springbt_security_jwt/util/JwtTokenUtil.java @@ -0,0 +1,128 @@ +package cn.codesheep.springbt_security_jwt.util; + +import cn.codesheep.springbt_security_jwt.comm.Const; +import cn.codesheep.springbt_security_jwt.model.entity.User; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * JWT 工具类 + * @www.codesheep.cn + * 20190312 + */ +@Component +public class JwtTokenUtil implements Serializable { + + private static final long serialVersionUID = -5625635588908941275L; + + private static final String CLAIM_KEY_USERNAME = "sub"; + private static final String CLAIM_KEY_CREATED = "created"; + + public String getUsernameFromToken(String token) { + String username; + try { + final Claims claims = getClaimsFromToken(token); + username = claims.getSubject(); + } catch (Exception e) { + username = null; + } + return username; + } + + public Date getCreatedDateFromToken(String token) { + Date created; + try { + final Claims claims = getClaimsFromToken(token); + created = new Date((Long) claims.get(CLAIM_KEY_CREATED)); + } catch (Exception e) { + created = null; + } + return created; + } + + public Date getExpirationDateFromToken(String token) { + Date expiration; + try { + final Claims claims = getClaimsFromToken(token); + expiration = claims.getExpiration(); + } catch (Exception e) { + expiration = null; + } + return expiration; + } + + private Claims getClaimsFromToken(String token) { + Claims claims; + try { + claims = Jwts.parser() + .setSigningKey( Const.SECRET ) + .parseClaimsJws(token) + .getBody(); + } catch (Exception e) { + claims = null; + } + return claims; + } + + private Date generateExpirationDate() { + return new Date(System.currentTimeMillis() + Const.EXPIRATION_TIME * 1000); + } + + private Boolean isTokenExpired(String token) { + final Date expiration = getExpirationDateFromToken(token); + return expiration.before(new Date()); + } + + private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) { + return (lastPasswordReset != null && created.before(lastPasswordReset)); + } + + public String generateToken(UserDetails userDetails) { + Map claims = new HashMap<>(); + claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername()); + claims.put(CLAIM_KEY_CREATED, new Date()); + return generateToken(claims); + } + + String generateToken(Map claims) { + return Jwts.builder() + .setClaims(claims) + .setExpiration(generateExpirationDate()) + .signWith(SignatureAlgorithm.HS512, Const.SECRET ) + .compact(); + } + + public Boolean canTokenBeRefreshed(String token) { + return !isTokenExpired(token); + } + + public String refreshToken(String token) { + String refreshedToken; + try { + final Claims claims = getClaimsFromToken(token); + claims.put(CLAIM_KEY_CREATED, new Date()); + refreshedToken = generateToken(claims); + } catch (Exception e) { + refreshedToken = null; + } + return refreshedToken; + } + + public Boolean validateToken(String token, UserDetails userDetails) { + User user = (User) userDetails; + final String username = getUsernameFromToken(token); + return ( + username.equals(user.getUsername()) + && !isTokenExpired(token) + ); + } +} + diff --git a/springbt_security_jwt/src/main/resources/application.properties b/springbt_security_jwt/src/main/resources/application.properties new file mode 100644 index 0000000..e745462 --- /dev/null +++ b/springbt_security_jwt/src/main/resources/application.properties @@ -0,0 +1,12 @@ +server.port=9991 + +spring.datasource.driver-class-name=com.mysql.jdbc.Driver +spring.datasource.url=jdbc:mysql://121.196.XXX.XXX:3306/spring_security_jwt?useUnicode=true&characterEncoding=utf-8 +spring.datasource.username=root +spring.datasource.password=XXXXXX + +logging.level.org.springframework.security=info + +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true +spring.jackson.serialization.indent_output=true diff --git a/springbt_security_jwt/src/test/java/cn/codesheep/springbt_security_jwt/SpringbtSecurityJwtApplicationTests.java b/springbt_security_jwt/src/test/java/cn/codesheep/springbt_security_jwt/SpringbtSecurityJwtApplicationTests.java new file mode 100644 index 0000000..463f07e --- /dev/null +++ b/springbt_security_jwt/src/test/java/cn/codesheep/springbt_security_jwt/SpringbtSecurityJwtApplicationTests.java @@ -0,0 +1,16 @@ +package cn.codesheep.springbt_security_jwt; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SpringbtSecurityJwtApplicationTests { + + @Test + public void contextLoads() { + } + +} -- GitLab