Sprint Boot使用OAuth和JWT实现身份认证【一】

举报
清雨小竹 发表于 2022/09/25 02:00:19 2022/09/25
【摘要】 依赖第三方库: compile 'io.jsonwebtoken:jjwt:0.9.0' 1.先写个例子用JWT实现获取token和解析token package com.yf.gyy.OAuthController; import java.util.Date;import java.util.HashMap;import java...

依赖第三方库

compile 'io.jsonwebtoken:jjwt:0.9.0'
 

1.先写个例子用JWT实现获取token和解析token


  
  1. package com.yf.gyy.OAuthController;
  2. import java.util.Date;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. import org.springframework.web.bind.annotation.RequestBody;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8. import io.jsonwebtoken.Claims;
  9. import io.jsonwebtoken.Jwts;
  10. import io.jsonwebtoken.SignatureAlgorithm;
  11. import io.swagger.annotations.Api;
  12. import io.swagger.annotations.ApiOperation;
  13. @RestController
  14. @Api(value="OAuth2测试")
  15. public class OAuthController {
  16. @ApiOperation(value="测试获取token",httpMethod="POST")
  17. @RequestMapping("/api/testOAuth/GetToken")
  18. public String CreateToken()
  19. {
  20. Map<String, Object> claims=new HashMap<String, Object>();
  21. claims.put("zzzili", "zz");
  22. String token = Jwts.builder()
  23. .setClaims(claims)
  24. .setExpiration(new Date(System.currentTimeMillis() + 6000 * 1000))
  25. .signWith(SignatureAlgorithm.HS512,"thisiskey") //采用什么算法是可以自己选择的,不一定非要采用HS512
  26. .compact();
  27. return token;
  28. }
  29. @ApiOperation(value="测试token解析",httpMethod="POST")
  30. @RequestMapping("/api/testOAuth/TestOAuth2")
  31. public Claims TestOAuth2( @RequestBody String token)
  32. {
  33. System.out.println(token);
  34. Claims claims = Jwts.parser()
  35. .setSigningKey("thisiskey")
  36. .parseClaimsJws(token)
  37. .getBody();
  38. return claims;
  39. }
  40. }

2.对spring boot项目添加OAuth过滤器

我们暂且实现,自己定义获取token的方法和自定义过滤器

需要4个java类

>>http请求过滤器类,继承自 OncePerRequestFilter

>>过滤器注册类,继承自 WebSecurityConfigurerAdapter

>>用户对象类,继承自 UserDetails

>>用户对象加密解密类

2.1添加一个rest方法,用以获取token:


  
  1. @ApiOperation(value="测试获取token",httpMethod="POST")
  2. @RequestMapping("/api/testOAuth2/GetToken")
  3. public String CreateToken()
  4. {
  5. List<String> roles = new ArrayList<String>();
  6. roles.add("USER");
  7. roles.add("ADMIN");
  8. Map<String, Object> u=new HashMap<String, Object>();
  9. u.put("password", "zzz");
  10. u.put("username", "zzz");
  11. u.put("created", "zzz");
  12. String token = Jwts.builder()
  13. .setClaims(u)
  14. .setExpiration(new Date(System.currentTimeMillis() + 6000 * 1000))
  15. .signWith(SignatureAlgorithm.HS512,"123456") //采用什么算法是可以自己选择的,不一定非要采用HS512
  16. .compact();
  17. return token;
  18. }

2.2自定义http请求过滤器


  
  1. package com.yf.gyy;
  2. import java.io.IOException;
  3. import java.util.ArrayList;
  4. import java.util.Calendar;
  5. import java.util.Date;
  6. import java.util.List;
  7. import javax.servlet.FilterChain;
  8. import javax.servlet.ServletException;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  13. import org.springframework.security.core.context.SecurityContextHolder;
  14. import org.springframework.security.core.userdetails.UserDetails;
  15. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  16. import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
  17. import org.springframework.stereotype.Component;
  18. import org.springframework.web.filter.OncePerRequestFilter;
  19. import io.jsonwebtoken.Claims;
  20. import io.jsonwebtoken.Jwts;
  21. @Component
  22. public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
  23. @Autowired
  24. private JwtTokenUtil jwtTokenUtil;
  25. @Override
  26. protected void doFilterInternal(
  27. HttpServletRequest request,
  28. HttpServletResponse response,
  29. FilterChain chain) throws ServletException, IOException {
  30. String tokenHeader = "Authorization";
  31. String tokenHead = "Bearer ";
  32. String authHeader = request.getHeader(tokenHeader);
  33. if (authHeader != null && authHeader.startsWith(tokenHead)) {
  34. final String authToken = authHeader.substring(tokenHead.length());
  35. Claims claims = Jwts.parser()
  36. .setSigningKey("123456")
  37. .parseClaimsJws(authToken)
  38. .getBody();
  39. String username = claims.get("username").toString();
  40. if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
  41. UserDetails userDetails = loadUserByUsername(username);
  42. if (jwtTokenUtil.validateToken(authToken, userDetails)) {
  43. UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
  44. userDetails, null, userDetails.getAuthorities());
  45. authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(
  46. request));
  47. //logger.info("authenticated user " + username + ", setting security context");
  48. SecurityContextHolder.getContext().setAuthentication(authentication);
  49. }
  50. }
  51. }
  52. chain.doFilter(request, response);
  53. }
  54. private UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  55. List<String> roles = new ArrayList<String>();
  56. roles.add("USER");
  57. roles.add("ADMIN");
  58. Calendar c = Calendar.getInstance();
  59. c.setTime(new Date());
  60. c.add(Calendar.DAY_OF_MONTH, 10);// 今天+10天
  61. Date nowT= c.getTime();
  62. JwtUser user = new JwtUser("zzz",
  63. "zzz",
  64. "zzz",
  65. "email",
  66. roles,
  67. nowT);
  68. return user;
  69. }
  70. }

  
  1. package com.yf.gyy;
  2. import java.io.Serializable;
  3. import java.util.Date;
  4. import java.util.Map;
  5. import org.springframework.security.core.userdetails.UserDetails;
  6. import org.springframework.stereotype.Component;
  7. import io.jsonwebtoken.Claims;
  8. import io.jsonwebtoken.Jwts;
  9. import io.jsonwebtoken.SignatureAlgorithm;
  10. /**
  11. * @author
  12. * JwtTokenUtil
  13. */
  14. //@Component("jwtTokenUtil")
  15. @Component
  16. public class JwtTokenUtil implements Serializable {
  17. private static final long serialVersionUID = -3301605591108950415L;
  18. static final String CLAIM_KEY_USERNAME = "username";
  19. static final String CLAIM_KEY_PASSWORD = "password";
  20. static final String CLAIM_KEY_CREATED = "created";
  21. //private static final String AUDIENCE_UNKNOWN = "unknown";
  22. //private static final String AUDIENCE_WEB = "web";
  23. //private static final String AUDIENCE_MOBILE = "mobile";
  24. //private static final String AUDIENCE_TABLET = "tablet";
  25. //通过@value注解获取密钥
  26. //@Value("123456")
  27. private String secret="123456";
  28. //通过@value注解获取失效时间
  29. //@Value("${jwt.expiration}")
  30. private Long expiration=300L;
  31. //@Resource(name = "tokenConfig")
  32. //private Map<String, String> tokenConfig;
  33. /**
  34. * @param token
  35. * return username by Token
  36. */
  37. public String getUsernameFromToken(String token) {
  38. String username;
  39. try {
  40. final Claims claims = getClaimsFromToken(token);
  41. username = (String) claims.get(CLAIM_KEY_USERNAME);
  42. //username = claims.getSubject();
  43. } catch (Exception e) {
  44. username = null;
  45. }
  46. return username;
  47. }
  48. /**
  49. * @param token
  50. * return CreatedDate by Token 获取token创建时间
  51. */
  52. public Date getCreatedDateFromToken(String token) {
  53. Date created;
  54. try {
  55. final Claims claims = getClaimsFromToken(token);
  56. created = new Date((Long) claims.get(CLAIM_KEY_CREATED));
  57. } catch (Exception e) {
  58. created = null;
  59. }
  60. return created;
  61. }
  62. /**
  63. * @param token
  64. * return ExpirationDate by Token 获取token过期时间
  65. */
  66. public Date getExpirationDateFromToken(String token) {
  67. Date expiration;
  68. try {
  69. final Claims claims = getClaimsFromToken(token);
  70. expiration = claims.getExpiration();
  71. } catch (Exception e) {
  72. expiration = null;
  73. }
  74. return expiration;
  75. }
  76. /**
  77. * @param token
  78. * return Password by Token 获取token的密码
  79. */
  80. public String getPasswordFromToken(String token) {
  81. String password;
  82. try {
  83. final Claims claims = getClaimsFromToken(token);
  84. password = (String) claims.get(CLAIM_KEY_PASSWORD);
  85. } catch (Exception e) {
  86. password = null;
  87. }
  88. return password;
  89. }
  90. public Claims getClaimsFromToken(String token) {
  91. Claims claims;
  92. try {
  93. claims = Jwts.parser()
  94. //设置签名的密钥
  95. .setSigningKey(secret)
  96. //把token转换成断言
  97. .parseClaimsJws(token)
  98. .getBody();
  99. //Date expirationTime = Jwts.parser().setSigningKey(secret).parseClaimsJwt(token).getBody().getExpiration();
  100. } catch (Exception e) {
  101. claims = null;
  102. }
  103. return claims;
  104. }
  105. //生成到期日期
  106. private Date generateExpirationDate() {
  107. return new Date(System.currentTimeMillis() + expiration * 1000);
  108. }
  109. //判断token是否过期
  110. private Boolean isTokenExpired(String token) {
  111. final Date expiration = getExpirationDateFromToken(token);
  112. return expiration.before(new Date());
  113. }
  114. //判断token创建时间是否在密码重置之前
  115. private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
  116. return (lastPasswordReset != null && created.before(lastPasswordReset));
  117. }
  118. /*private String generateAudience(Device device) {
  119. String audience = AUDIENCE_UNKNOWN;
  120. if (device.isNormal()) {
  121. audience = AUDIENCE_WEB;
  122. } else if (device.isTablet()) {
  123. audience = AUDIENCE_TABLET;
  124. } else if (device.isMobile()) {
  125. audience = AUDIENCE_MOBILE;
  126. }
  127. return audience;
  128. }
  129. //忽略token的过期时间
  130. private Boolean ignoreTokenExpiration(String token) {
  131. String audience = getPasswordFromToken(token);
  132. return (AUDIENCE_TABLET.equals(audience) || AUDIENCE_MOBILE.equals(audience));
  133. }*/
  134. //生成token
  135. public String generateToken(Map<String, Object> claims) {
  136. return Jwts.builder()
  137. .setClaims(claims)
  138. .setExpiration(generateExpirationDate())
  139. .signWith(SignatureAlgorithm.HS512, secret)
  140. .compact();
  141. }
  142. //判断token是否可以刷新
  143. public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
  144. final Date created = getCreatedDateFromToken(token);
  145. return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
  146. && (!isTokenExpired(token)) ;
  147. /*|| ignoreTokenExpiration(token))*/
  148. }
  149. //刷新token
  150. public String refreshToken(String token) {
  151. String refreshedToken;
  152. try {
  153. final Claims claims = getClaimsFromToken(token);
  154. claims.put(CLAIM_KEY_CREATED, new Date());
  155. refreshedToken = generateToken(claims);
  156. } catch (Exception e) {
  157. refreshedToken = null;
  158. }
  159. return refreshedToken;
  160. }
  161. //判读token是否有效
  162. public Boolean validateToken(String token, UserDetails userDomain) {
  163. // JwtUser user = (JwtUser) userPO;
  164. final String username = getUsernameFromToken(token);
  165. //final Date created = getCreatedDateFromToken(token);
  166. //final Date expiration = getExpirationDateFromToken(token);
  167. if(username==null){
  168. return false;
  169. }else{
  170. return (
  171. username.equals(userDomain.getUsername())
  172. && !isTokenExpired(token));
  173. //&& !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate()));
  174. }
  175. }
  176. //public String getTokenKey() {
  177. // return tokenConfig.get("tokenKey");
  178. //}
  179. }


  
  1. package com.yf.gyy;
  2. import java.util.Collection;
  3. import java.util.Date;
  4. import java.util.List;
  5. import java.util.stream.Collectors;
  6. import org.springframework.security.core.GrantedAuthority;
  7. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  8. import org.springframework.security.core.userdetails.UserDetails;
  9. import com.fasterxml.jackson.annotation.JsonIgnore;
  10. public class JwtUser implements UserDetails {
  11. /**
  12. *
  13. */
  14. private static final long serialVersionUID = 1L;
  15. private final String id;
  16. private final String username;
  17. private final String password;
  18. private final String email;
  19. private final Collection<? extends GrantedAuthority> authorities;
  20. private final Date lastPasswordResetDate;
  21. public JwtUser(
  22. String id,
  23. String username,
  24. String password,
  25. String email,
  26. List<String> authorities,
  27. Date lastPasswordResetDate) {
  28. this.id = id;
  29. this.username = username;
  30. this.password = password;
  31. this.email = email;
  32. this.authorities = mapToGrantedAuthorities(authorities);
  33. this.lastPasswordResetDate = lastPasswordResetDate;
  34. }
  35. private List<GrantedAuthority> mapToGrantedAuthorities(List<String> authorities) {
  36. return authorities.stream()
  37. .map(SimpleGrantedAuthority::new)
  38. .collect(Collectors.toList());
  39. }
  40. //返回分配给用户的角色列表
  41. @Override
  42. public Collection<? extends GrantedAuthority> getAuthorities() {
  43. return authorities;
  44. }
  45. @JsonIgnore
  46. public String getId() {
  47. return id;
  48. }
  49. @JsonIgnore
  50. @Override
  51. public String getPassword() {
  52. return password;
  53. }
  54. @Override
  55. public String getUsername() {
  56. return username;
  57. }
  58. // 账户是否未过期
  59. @JsonIgnore
  60. @Override
  61. public boolean isAccountNonExpired() {
  62. return true;
  63. }
  64. // 账户是否未锁定
  65. @JsonIgnore
  66. @Override
  67. public boolean isAccountNonLocked() {
  68. return true;
  69. }
  70. // 密码是否未过期
  71. @JsonIgnore
  72. @Override
  73. public boolean isCredentialsNonExpired() {
  74. return true;
  75. }
  76. // 账户是否激活
  77. @JsonIgnore
  78. @Override
  79. public boolean isEnabled() {
  80. return true;
  81. }
  82. // 这个是自定义的,返回上次密码重置日期
  83. @JsonIgnore
  84. public Date getLastPasswordResetDate() {
  85. return lastPasswordResetDate;
  86. }
  87. public String getEmail() {
  88. return email;
  89. }
  90. }

2.3将过滤器装在到webconfig中


  
  1. package com.yf.gyy;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.http.HttpMethod;
  6. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  7. import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  8. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  9. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  10. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  11. import org.springframework.security.config.http.SessionCreationPolicy;
  12. import org.springframework.security.core.userdetails.UserDetailsService;
  13. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  14. import org.springframework.security.crypto.password.PasswordEncoder;
  15. import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
  16. @Configuration
  17. @EnableWebSecurity
  18. @EnableGlobalMethodSecurity(prePostEnabled = true)
  19. public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
  20. @Override
  21. protected void configure(HttpSecurity httpSecurity) throws Exception {
  22. httpSecurity
  23. .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
  24. .csrf().disable()
  25. .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
  26. .requestMatchers().anyRequest();
  27. }
  28. @Bean
  29. public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
  30. return new JwtAuthenticationTokenFilter();
  31. }
  32. }

3.在rest接口中使用标注添加访问权限:


  
  1. package com.yf.gyy.OAuthController;
  2. import org.springframework.security.access.prepost.PreAuthorize;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.RestController;
  5. import io.swagger.annotations.Api;
  6. import io.swagger.annotations.ApiOperation;
  7. @RestController
  8. @Api(value="OAuth2测试")
  9. //@PreAuthorize("hasRole('ROLE_USER')") //判断角色
  10. @PreAuthorize("principal.username!=null") //用户名不为空
  11. public class OAuthController {
  12. @ApiOperation(value="测试访问授权",httpMethod="POST")
  13. @RequestMapping("/api/testOAuth/TestAccessToken")
  14. public String TestAccessToken()
  15. {
  16. return "test oauth";
  17. }
  18. }

文章来源: zzzili.blog.csdn.net,作者:清雨小竹,版权归原作者所有,如需转载,请联系作者。

原文链接:zzzili.blog.csdn.net/article/details/79383919

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。