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

举报
清雨小竹 发表于 2022/09/25 01:15:38 2022/09/25
【摘要】 上一篇文章已经实现了自定义获取token方法和自定义过滤器,本篇文章对自定义类进行封装: 文件结构: 依赖: dependencies { compile('com.github.wenhao:jpa-spec:3.1.1') compile('io.springfox:springfox-swagger2:2.2....

上一篇文章已经实现了自定义获取token方法和自定义过滤器,本篇文章对自定义类进行封装:

文件结构:


依赖:


  
  1. dependencies {
  2. compile('com.github.wenhao:jpa-spec:3.1.1')
  3. compile('io.springfox:springfox-swagger2:2.2.2')
  4. compile('io.springfox:springfox-swagger-ui:2.2.2')
  5. compile 'io.jsonwebtoken:jjwt:0.9.0'
  6. compile 'com.alibaba:fastjson:1.2.44'
  7. compile('org.springframework.security:spring-security-jwt')
  8. compile('org.springframework.boot:spring-boot-starter-security')
  9. compile('org.springframework.security.oauth:spring-security-oauth2')
  10. compile('org.springframework.boot:spring-boot-starter-data-jpa')
  11. compile('org.springframework.boot:spring-boot-starter-jdbc')
  12. compile('org.springframework.boot:spring-boot-starter-web')
  13. runtime('mysql:mysql-connector-java')
  14. providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
  15. testCompile('org.springframework.boot:spring-boot-starter-test')
  16. }



  
  1. package com.yf.gyy.OAuthConfig;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  5. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  6. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  7. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  8. import org.springframework.security.config.http.SessionCreationPolicy;
  9. import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
  10. @Configuration
  11. @EnableWebSecurity
  12. @EnableGlobalMethodSecurity(prePostEnabled = true)
  13. public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
  14. @Override
  15. protected void configure(HttpSecurity httpSecurity) throws Exception {
  16. httpSecurity
  17. .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
  18. .csrf().disable()
  19. .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
  20. .requestMatchers().anyRequest();
  21. }
  22. @Bean
  23. public JWTAuthenticationFilter authenticationTokenFilterBean() throws Exception {
  24. return new JWTAuthenticationFilter();
  25. }
  26. }



  
  1. package com.yf.gyy.OAuthConfig;
  2. import java.io.IOException;
  3. import javax.servlet.FilterChain;
  4. import javax.servlet.ServletException;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  9. import org.springframework.security.core.context.SecurityContextHolder;
  10. import org.springframework.security.core.userdetails.UserDetails;
  11. import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
  12. import org.springframework.stereotype.Component;
  13. import org.springframework.web.filter.OncePerRequestFilter;
  14. import io.jsonwebtoken.Claims;
  15. import io.jsonwebtoken.Jwts;
  16. @Component
  17. public class JWTAuthenticationFilter extends OncePerRequestFilter {
  18. @Autowired
  19. private JWTUtils jwtTokenUtil;
  20. @Override
  21. protected void doFilterInternal(
  22. HttpServletRequest request,
  23. HttpServletResponse response,
  24. FilterChain chain) throws ServletException, IOException {
  25. String tokenHeader = "Authorization";
  26. String tokenHead = "Bearer ";
  27. String authHeader = request.getHeader(tokenHeader);
  28. if (authHeader != null && authHeader.startsWith(tokenHead)) {
  29. final String authToken = authHeader.substring(tokenHead.length());
  30. Claims claims = Jwts.parser()
  31. .setSigningKey(JWTUtils.secret)
  32. .parseClaimsJws(authToken)
  33. .getBody();
  34. UserDetails userDetails = jwtTokenUtil.getUserFromToken(claims);
  35. if (jwtTokenUtil.validateToken(authToken, userDetails)) {
  36. UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
  37. authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
  38. SecurityContextHolder.getContext().setAuthentication(authentication);
  39. }
  40. }
  41. chain.doFilter(request, response);
  42. }
  43. }


  
  1. package com.yf.gyy.OAuthConfig;
  2. import java.util.Collection;
  3. import org.springframework.security.core.GrantedAuthority;
  4. import org.springframework.security.core.userdetails.UserDetails;
  5. public class JWTUserDetails implements UserDetails {
  6. private String userId;
  7. private String password;
  8. private final String username;
  9. private final Collection<? extends GrantedAuthority> authorities;
  10. private final boolean accountNonExpired;
  11. private final boolean accountNonLocked;
  12. private final boolean credentialsNonExpired;
  13. private final boolean enabled;
  14. public JWTUserDetails(String userId, String username, String password, Collection<? extends GrantedAuthority> authorities) {
  15. this(userId, username, password, true, true, true, true, authorities);
  16. }
  17. public JWTUserDetails(String userId, String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
  18. if (username != null && !"".equals(username) && password != null) {
  19. this.userId = userId;
  20. this.username = username;
  21. this.password = password;
  22. this.enabled = enabled;
  23. this.accountNonExpired = accountNonExpired;
  24. this.credentialsNonExpired = credentialsNonExpired;
  25. this.accountNonLocked = accountNonLocked;
  26. this.authorities = authorities;
  27. } else {
  28. throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
  29. }
  30. }
  31. @Override
  32. public Collection<? extends GrantedAuthority> getAuthorities() {
  33. return authorities;
  34. }
  35. public String getUserId() {
  36. return userId;
  37. }
  38. @Override
  39. public String getPassword() {
  40. return password;
  41. }
  42. @Override
  43. public String getUsername() {
  44. return username;
  45. }
  46. @Override
  47. public boolean isAccountNonExpired() {
  48. return accountNonExpired;
  49. }
  50. @Override
  51. public boolean isAccountNonLocked() {
  52. return accountNonLocked;
  53. }
  54. @Override
  55. public boolean isCredentialsNonExpired() {
  56. return credentialsNonExpired;
  57. }
  58. @Override
  59. public boolean isEnabled() {
  60. return enabled;
  61. }
  62. }


  
  1. package com.yf.gyy.OAuthConfig;
  2. import java.util.ArrayList;
  3. import java.util.Collection;
  4. import java.util.Date;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import java.util.Map;
  8. import java.util.UUID;
  9. import org.springframework.security.core.GrantedAuthority;
  10. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  11. import org.springframework.security.core.userdetails.UserDetails;
  12. import org.springframework.stereotype.Component;
  13. import com.alibaba.fastjson.JSON;
  14. import io.jsonwebtoken.Claims;
  15. import io.jsonwebtoken.CompressionCodecs;
  16. import io.jsonwebtoken.Jwts;
  17. import io.jsonwebtoken.SignatureAlgorithm;
  18. @Component
  19. public class JWTUtils {
  20. public static final String ROLE_REFRESH_TOKEN = "ROLE_REFRESH_TOKEN";
  21. private static final String CLAIM_KEY_USER_ID = "user_id";
  22. private static final String CLAIM_KEY_AUTHORITIES = "scope";
  23. private static final String CLAIM_KEY_ACCOUNT_ENABLED = "enabled";
  24. private static final String CLAIM_KEY_ACCOUNT_NON_LOCKED = "non_locked";
  25. private static final String CLAIM_KEY_ACCOUNT_NON_EXPIRED = "non_expired";
  26. public static String secret = "123456";
  27. private static Long access_token_expiration = 30000L;
  28. private static Long refresh_token_expiration = 30000L;
  29. /*@Value("${jwt.secret}")
  30. private String secret;
  31. @Value("${jwt.access_token.expiration}")
  32. private Long access_token_expiration;
  33. @Value("${jwt.refresh_token.expiration}")
  34. private Long refresh_token_expiration;*/
  35. private final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS256;
  36. public JWTUserDetails getUserFromToken(String token) {
  37. JWTUserDetails user;
  38. try {
  39. final Claims claims = getClaimsFromToken(token);
  40. String userId = getUserIdFromToken(token);
  41. String username = claims.getSubject();
  42. List roles = (List) claims.get(CLAIM_KEY_AUTHORITIES);
  43. Collection<? extends GrantedAuthority> authorities = parseArrayToAuthorities(roles);
  44. boolean account_enabled = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_ENABLED);
  45. boolean account_non_locked = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_NON_LOCKED);
  46. boolean account_non_expired = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_NON_EXPIRED);
  47. user = new JWTUserDetails(userId, username, "password", account_enabled, account_non_expired, true, account_non_locked, authorities);
  48. } catch (Exception e) {
  49. user = null;
  50. }
  51. return user;
  52. }
  53. public JWTUserDetails getUserFromToken(Claims claims) {
  54. JWTUserDetails user;
  55. try {
  56. //final Claims claims = getClaimsFromToken(token);
  57. String userId = claims.get(CLAIM_KEY_USER_ID).toString();//getUserIdFromToken(token);
  58. String username = claims.get(CLAIM_KEY_USER_ID).toString();//claims.getSubject();
  59. List roles = (List) claims.get(CLAIM_KEY_AUTHORITIES);
  60. Collection<? extends GrantedAuthority> authorities = parseArrayToAuthorities(roles);
  61. boolean account_enabled = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_ENABLED);
  62. boolean account_non_locked = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_NON_LOCKED);
  63. boolean account_non_expired = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_NON_EXPIRED);
  64. user = new JWTUserDetails(userId, username, "password", account_enabled, account_non_expired, true, account_non_locked, authorities);
  65. } catch (Exception e) {
  66. user = null;
  67. }
  68. return user;
  69. }
  70. public String getUserIdFromToken(String token) {
  71. String userId;
  72. try {
  73. final Claims claims = getClaimsFromToken(token);
  74. userId = claims.get(CLAIM_KEY_USER_ID).toString();
  75. } catch (Exception e) {
  76. userId = "";
  77. }
  78. return userId;
  79. }
  80. public String getUsernameFromToken(String token) {
  81. String username;
  82. try {
  83. final Claims claims = getClaimsFromToken(token);
  84. username = claims.get(CLAIM_KEY_USER_ID).toString();
  85. } catch (Exception e) {
  86. username = null;
  87. }
  88. return username;
  89. }
  90. public Date getCreatedDateFromToken(String token) {
  91. Date created;
  92. try {
  93. final Claims claims = getClaimsFromToken(token);
  94. created = claims.getIssuedAt();
  95. } catch (Exception e) {
  96. created = null;
  97. }
  98. return created;
  99. }
  100. public Date getExpirationDateFromToken(String token) {
  101. Date expiration;
  102. try {
  103. final Claims claims = getClaimsFromToken(token);
  104. expiration = claims.getExpiration();
  105. } catch (Exception e) {
  106. expiration = null;
  107. }
  108. return expiration;
  109. }
  110. private Claims getClaimsFromToken(String token) {
  111. Claims claims;
  112. try {
  113. claims = Jwts.parser()
  114. .setSigningKey(secret)
  115. .parseClaimsJws(token)
  116. .getBody();
  117. } catch (Exception e) {
  118. claims = null;
  119. }
  120. return claims;
  121. }
  122. private Date generateExpirationDate(long expiration) {
  123. return new Date(System.currentTimeMillis() + expiration * 1000);
  124. }
  125. private Boolean isTokenExpired(String token) {
  126. final Date expiration = getExpirationDateFromToken(token);
  127. return expiration.before(new Date());
  128. }
  129. private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
  130. return (lastPasswordReset != null && created.before(lastPasswordReset));
  131. }
  132. public String generateAccessToken(UserDetails userDetails) {
  133. JWTUserDetails user = (JWTUserDetails) userDetails;
  134. Map<String, Object> claims = generateClaims(user);
  135. claims.put(CLAIM_KEY_AUTHORITIES, JSON.toJSON(authoritiesToArray(user.getAuthorities())));
  136. return generateAccessToken(user.getUsername(), claims);
  137. }
  138. public Map<String, Object> generateAccessTokenToMap(UserDetails userDetails) {
  139. JWTUserDetails user = (JWTUserDetails) userDetails;
  140. Map<String, Object> claims = generateClaims(user);
  141. claims.put(CLAIM_KEY_AUTHORITIES, JSON.toJSON(authoritiesToArray(user.getAuthorities())));
  142. return claims;
  143. }
  144. private Map<String, Object> generateClaims(JWTUserDetails user) {
  145. Map<String, Object> claims = new HashMap<>();
  146. claims.put(CLAIM_KEY_USER_ID, user.getUserId());
  147. claims.put(CLAIM_KEY_ACCOUNT_ENABLED, user.isEnabled());
  148. claims.put(CLAIM_KEY_ACCOUNT_NON_LOCKED, user.isAccountNonLocked());
  149. claims.put(CLAIM_KEY_ACCOUNT_NON_EXPIRED, user.isAccountNonExpired());
  150. return claims;
  151. }
  152. private String generateAccessToken(String subject, Map<String, Object> claims) {
  153. return generateToken(subject, claims, access_token_expiration);
  154. }
  155. private List authoritiesToArray(Collection<? extends GrantedAuthority> authorities) {
  156. List<String> list = new ArrayList<>();
  157. for (GrantedAuthority ga : authorities) {
  158. list.add(ga.getAuthority());
  159. }
  160. return list;
  161. }
  162. private Collection<? extends GrantedAuthority> parseArrayToAuthorities(List roles) {
  163. Collection<GrantedAuthority> authorities = new ArrayList<>();
  164. SimpleGrantedAuthority authority;
  165. for (Object role : roles) {
  166. authority = new SimpleGrantedAuthority(role.toString());
  167. authorities.add(authority);
  168. }
  169. return authorities;
  170. }
  171. public String generateRefreshToken(UserDetails userDetails) {
  172. JWTUserDetails user = (JWTUserDetails) userDetails;
  173. Map<String, Object> claims = generateClaims(user);
  174. // 只授于更新 token 的权限
  175. String roles[] = new String[]{JWTUtils.ROLE_REFRESH_TOKEN};
  176. claims.put(CLAIM_KEY_AUTHORITIES, JSON.toJSON(roles));
  177. return generateRefreshToken(user.getUsername(), claims);
  178. }
  179. private String generateRefreshToken(String subject, Map<String, Object> claims) {
  180. return generateToken(subject, claims, refresh_token_expiration);
  181. }
  182. public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
  183. final Date created = getCreatedDateFromToken(token);
  184. return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
  185. && (!isTokenExpired(token));
  186. }
  187. public String refreshToken(String token) {
  188. String refreshedToken;
  189. try {
  190. final Claims claims = getClaimsFromToken(token);
  191. refreshedToken = generateAccessToken(claims.getSubject(), claims);
  192. } catch (Exception e) {
  193. refreshedToken = null;
  194. }
  195. return refreshedToken;
  196. }
  197. private String generateToken(String subject, Map<String, Object> claims, long expiration) {
  198. return Jwts.builder()
  199. .setClaims(claims)
  200. .setSubject(subject)
  201. .setId(UUID.randomUUID().toString())
  202. .setIssuedAt(new Date())
  203. .setExpiration(generateExpirationDate(expiration))
  204. .compressWith(CompressionCodecs.DEFLATE)
  205. .signWith(SIGNATURE_ALGORITHM, secret)
  206. .compact();
  207. }
  208. public Boolean validateToken(String token, UserDetails userDetails) {
  209. JWTUserDetails user = (JWTUserDetails) userDetails;
  210. final String userId = getUserIdFromToken(token);
  211. final String username = getUsernameFromToken(token);
  212. // final Date created = getCreatedDateFromToken(token);
  213. // final Date expiration = getExpirationDateFromToken(token);
  214. return (userId.equals(user.getUserId())
  215. && username.equals(user.getUsername())
  216. && !isTokenExpired(token)
  217. /* && !isCreatedBeforeLastPasswordReset(created, userDetails.getLastPasswordResetDate()) */
  218. );
  219. }
  220. }



  
  1. package com.yf.gyy.OAuthController;
  2. import java.util.ArrayList;
  3. import java.util.Calendar;
  4. import java.util.Date;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import java.util.Map;
  8. import java.util.stream.Collectors;
  9. import org.springframework.security.core.GrantedAuthority;
  10. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  11. import org.springframework.web.bind.annotation.RequestBody;
  12. import org.springframework.web.bind.annotation.RequestMapping;
  13. import org.springframework.web.bind.annotation.RestController;
  14. import com.yf.gyy.OAuthConfig.JWTUserDetails;
  15. import com.yf.gyy.OAuthConfig.JWTUtils;
  16. import io.jsonwebtoken.Claims;
  17. import io.jsonwebtoken.Jwts;
  18. import io.jsonwebtoken.SignatureAlgorithm;
  19. import io.swagger.annotations.Api;
  20. import io.swagger.annotations.ApiOperation;
  21. @RestController
  22. @Api(value="OAuth2测试")
  23. public class OAuthController2 {
  24. @ApiOperation(value="测试获取token",httpMethod="POST")
  25. @RequestMapping("/api/testOAuth2/GetToken")
  26. public String CreateToken()
  27. {
  28. List<String> roles = new ArrayList<String>();
  29. roles.add("USER");
  30. roles.add("ADMIN");
  31. JWTUserDetails user = new JWTUserDetails("zzz",
  32. "zzz",
  33. "zzz",
  34. mapToGrantedAuthorities(roles));
  35. JWTUtils jwtUtils = new JWTUtils();
  36. Map<String, Object> claims = jwtUtils.generateAccessTokenToMap(user);
  37. String token = Jwts.builder()
  38. .setClaims(claims)
  39. .setExpiration(new Date(System.currentTimeMillis() + 6000 * 1000))
  40. .signWith(SignatureAlgorithm.HS512,"123456") //采用什么算法是可以自己选择的,不一定非要采用HS512
  41. .compact();
  42. return token;
  43. }
  44. private List<GrantedAuthority> mapToGrantedAuthorities(List<String> authorities) {
  45. return authorities.stream()
  46. .map(SimpleGrantedAuthority::new)
  47. .collect(Collectors.toList());
  48. }
  49. @ApiOperation(value="测试token解析",httpMethod="POST")
  50. @RequestMapping("/api/testOAuth2/TestOAuth2")
  51. public Claims TestOAuth2( @RequestBody String token)
  52. {
  53. System.out.println(token);
  54. Claims claims = Jwts.parser()
  55. .setSigningKey("123456")
  56. .parseClaimsJws(token)
  57. .getBody();
  58. return claims;
  59. }
  60. }

    


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

生成token接口:http://127.0.0.1:8080/api/testOAuth2/GetToken



授权访问接口:http://127.0.0.1:8080/api/testOAuth/TestAccessToken



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

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

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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