国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Springboot集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的步驟詳解

Springboot集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的步驟詳解

2021-08-05 11:06南瓜慢說 Java教程

這篇文章主要介紹了Springboot集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的步驟詳解,幫助大家更好的理解和使用springboot,感興趣的朋友可以了解下

1 簡介

Spring Security作為成熟且強(qiáng)大的安全框架,得到許多大廠的青睞。而作為前后端分離的SSO方案,JWT也在許多項(xiàng)目中應(yīng)用。本文將介紹如何通過Spring Security實(shí)現(xiàn)JWT認(rèn)證。

用戶與服務(wù)器交互大概如下:

Springboot集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的步驟詳解

  1. 客戶端獲取JWT,一般通過POST方法把用戶名/密碼傳給server;
  2. 服務(wù)端接收到客戶端的請求后,會檢驗(yàn)用戶名/密碼是否正確,如果正確則生成JWT并返回;不正確則返回錯誤;
  3. 客戶端拿到JWT后,在有效期內(nèi)都可以通過JWT來訪問資源了,一般把JWT放在請求頭;一次獲取,多次使用;
  4. 服務(wù)端校驗(yàn)JWT是否合法,合法則允許客戶端正常訪問,不合法則返回401。

2 項(xiàng)目整合

我們把要整合的Spring Security和JWT加入到項(xiàng)目的依賴中去:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-security</artifactId>
  8. </dependency>
  9. <dependency>
  10. <groupId>io.jsonwebtoken</groupId>
  11. <artifactId>jjwt</artifactId>
  12. <version>0.9.1</version>
  13. </dependency>

2.1 JWT整合

2.1.1 JWT工具類

JWT工具類起碼要具有以下功能:

  • 根據(jù)用戶信息生成JWT;
  • 校驗(yàn)JWT是否合法,如是否被篡改、是否過期等;
  • 從JWT中解析用戶信息,如用戶名、權(quán)限等;

具體代碼如下:

  1. @Component
  2. public class JwtTokenProvider {
  3.  
  4. @Autowired JwtProperties jwtProperties;
  5.  
  6. @Autowired
  7. private CustomUserDetailsService userDetailsService;
  8.  
  9. private String secretKey;
  10.  
  11. @PostConstruct
  12. protected void init() {
  13. secretKey = Base64.getEncoder().encodeToString(jwtProperties.getSecretKey().getBytes());
  14. }
  15.  
  16. public String createToken(String username, List<String> roles) {
  17.  
  18. Claims claims = Jwts.claims().setSubject(username);
  19. claims.put("roles", roles);
  20.  
  21. Date now = new Date();
  22. Date validity = new Date(now.getTime() + jwtProperties.getValidityInMs());
  23.  
  24. return Jwts.builder()//
  25. .setClaims(claims)//
  26. .setIssuedAt(now)//
  27. .setExpiration(validity)//
  28. .signWith(SignatureAlgorithm.HS256, secretKey)//
  29. .compact();
  30. }
  31.  
  32. public Authentication getAuthentication(String token) {
  33. UserDetails userDetails = this.userDetailsService.loadUserByUsername(getUsername(token));
  34. return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
  35. }
  36.  
  37. public String getUsername(String token) {
  38. return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
  39. }
  40.  
  41. public String resolveToken(HttpServletRequest req) {
  42. String bearerToken = req.getHeader("Authorization");
  43. if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
  44. return bearerToken.substring(7);
  45. }
  46. return null;
  47. }
  48.  
  49. public boolean validateToken(String token) {
  50. try {
  51. Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
  52.  
  53. if (claims.getBody().getExpiration().before(new Date())) {
  54. return false;
  55. }
  56.  
  57. return true;
  58. } catch (JwtException | IllegalArgumentException e) {
  59. throw new InvalidJwtAuthenticationException("Expired or invalid JWT token");
  60. }
  61. }
  62.  
  63. }

工具類還實(shí)現(xiàn)了另一個功能:從HTTP請求頭中獲取JWT。

2.1.2 Token處理的Filter

Filter是Security處理的關(guān)鍵,基本上都是通過Filter來攔截請求的。首先從請求頭取出JWT,然后校驗(yàn)JWT是否合法,如果合法則取出Authentication保存在SecurityContextHolder里。如果不合法,則做異常處理。

  1. public class JwtTokenAuthenticationFilter extends GenericFilterBean {
  2.  
  3. private JwtTokenProvider jwtTokenProvider;
  4.  
  5. public JwtTokenAuthenticationFilter(JwtTokenProvider jwtTokenProvider) {
  6. this.jwtTokenProvider = jwtTokenProvider;
  7. }
  8.  
  9. @Override
  10. public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
  11. throws IOException, ServletException {
  12. HttpServletRequest request = (HttpServletRequest) req;
  13. HttpServletResponse response = (HttpServletResponse) res;
  14.  
  15. try {
  16. String token = jwtTokenProvider.resolveToken(request);
  17. if (token != null && jwtTokenProvider.validateToken(token)) {
  18. Authentication auth = jwtTokenProvider.getAuthentication(token);
  19.  
  20. if (auth != null) {
  21. SecurityContextHolder.getContext().setAuthentication(auth);
  22. }
  23. }
  24. } catch (InvalidJwtAuthenticationException e) {
  25. response.setStatus(HttpStatus.UNAUTHORIZED.value());
  26. response.getWriter().write("Invalid token");
  27. response.getWriter().flush();
  28. return;
  29. }
  30.  
  31. filterChain.doFilter(req, res);
  32. }
  33. }

對于異常處理,使用@ControllerAdvice是不行的,應(yīng)該這個是Filter,在這里拋的異常還沒有到DispatcherServlet,無法處理。所以Filter要自己做異常處理:

  1. catch (InvalidJwtAuthenticationException e) {
  2. response.setStatus(HttpStatus.UNAUTHORIZED.value());
  3. response.getWriter().write("Invalid token");
  4. response.getWriter().flush();
  5. return;
  6. }

最后的return不能省略,因?yàn)橐呀?jīng)要把輸出的內(nèi)容給Response了,沒有必要再往后傳遞,否則報錯

  1. java.lang.IllegalStateException: getWriter() has already been called

2.1.3 JWT屬性

JWT需要配置一個密鑰來加密,同時還要配置JWT令牌的有效期。

  1. @Configuration
  2. @ConfigurationProperties(prefix = "pkslow.jwt")
  3. public class JwtProperties {
  4. private String secretKey = "pkslow.key";
  5. private long validityInMs = 3600_000;
  6. //getter and setter
  7. }

2.2 Spring Security整合

Spring Security的整個框架還是比較復(fù)雜的,簡化后大概如下圖所示:

Springboot集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的步驟詳解

它是通過一連串的Filter來進(jìn)行安全管理。細(xì)節(jié)這里先不展開講。

2.2.1 WebSecurityConfigurerAdapter配置

這個配置也可以理解為是FilterChain的配置,可以不用理解,代碼很好懂它做了什么:

  1. @Configuration
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  3.  
  4. @Autowired
  5. JwtTokenProvider jwtTokenProvider;
  6.  
  7. @Bean
  8. @Override
  9. public AuthenticationManager authenticationManagerBean() throws Exception {
  10. return super.authenticationManagerBean();
  11. }
  12.  
  13. @Bean
  14. public PasswordEncoder passwordEncoder() {
  15. return NoOpPasswordEncoder.getInstance();
  16. }
  17.  
  18. @Override
  19. protected void configure(HttpSecurity http) throws Exception {
  20. http
  21. .httpBasic().disable()
  22. .csrf().disable()
  23. .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  24. .and()
  25. .authorizeRequests()
  26. .antMatchers("/auth/login").permitAll()
  27. .antMatchers(HttpMethod.GET, "/admin").hasRole("ADMIN")
  28. .antMatchers(HttpMethod.GET, "/user").hasRole("USER")
  29. .anyRequest().authenticated()
  30. .and()
  31. .apply(new JwtSecurityConfigurer(jwtTokenProvider));
  32. }
  33. }

這里通過HttpSecurity配置了哪些請求需要什么權(quán)限才可以訪問。

  • /auth/login用于登陸獲取JWT,所以都能訪問;
  • /admin只有ADMIN用戶才可以訪問;
  • /user只有USER用戶才可以訪問。

而之前實(shí)現(xiàn)的Filter則在下面配置使用:

  1. public class JwtSecurityConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
  2.  
  3. private JwtTokenProvider jwtTokenProvider;
  4.  
  5. public JwtSecurityConfigurer(JwtTokenProvider jwtTokenProvider) {
  6. this.jwtTokenProvider = jwtTokenProvider;
  7. }
  8.  
  9. @Override
  10. public void configure(HttpSecurity http) throws Exception {
  11. JwtTokenAuthenticationFilter customFilter = new JwtTokenAuthenticationFilter(jwtTokenProvider);
  12. http.exceptionHandling()
  13. .authenticationEntryPoint(new JwtAuthenticationEntryPoint())
  14. .and()
  15. .addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
  16. }
  17. }

2.2.2 用戶從哪來

通常在Spring Security的世界里,都是通過實(shí)現(xiàn)UserDetailsService來獲取UserDetails的。

  1. @Component
  2. public class CustomUserDetailsService implements UserDetailsService {
  3.  
  4. private UserRepository users;
  5.  
  6. public CustomUserDetailsService(UserRepository users) {
  7. this.users = users;
  8. }
  9.  
  10. @Override
  11. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  12. return this.users.findByUsername(username)
  13. .orElseThrow(() -> new UsernameNotFoundException("Username: " + username + " not found"));
  14. }
  15. }

對于UserRepository,可以從數(shù)據(jù)庫中讀取,或者其它用戶管理中心。為了方便,我使用Map放了兩個用戶:

  1. @Repository
  2. public class UserRepository {
  3.  
  4. private static final Map<String, User> allUsers = new HashMap<>();
  5.  
  6. @Autowired
  7. private PasswordEncoder passwordEncoder;
  8.  
  9. @PostConstruct
  10. protected void init() {
  11. allUsers.put("pkslow", new User("pkslow", passwordEncoder.encode("123456"), Collections.singletonList("ROLE_ADMIN")));
  12. allUsers.put("user", new User("user", passwordEncoder.encode("123456"), Collections.singletonList("ROLE_USER")));
  13. }
  14.  
  15. public Optional<User> findByUsername(String username) {
  16. return Optional.ofNullable(allUsers.get(username));
  17. }
  18. }

3 測試

完成代碼編寫后,我們來測試一下:

(1)無JWT訪問,失敗

  1. curl http://localhost:8080/admin
  2. {"timestamp":"2021-02-06T05:45:06.385+0000","status":403,"error":"Forbidden","message":"Access Denied","path":"/admin"}
  3.  
  4. $ curl http://localhost:8080/user
  5. {"timestamp":"2021-02-06T05:45:16.438+0000","status":403,"error":"Forbidden","message":"Access Denied","path":"/user"}

(2)admin獲取JWT,密碼錯誤則失敗,密碼正確則成功

  1. $ curl http://localhost:8080/auth/login -X POST -d '{"username":"pkslow","password":"xxxxxx"}' -H 'Content-Type: application/json'
  2. {"timestamp":"2021-02-06T05:47:16.254+0000","status":403,"error":"Forbidden","message":"Access Denied","path":"/auth/login"}
  3.  
  4. $ curl http://localhost:8080/auth/login -X POST -d '{"username":"pkslow","password":"123456"}' -H 'Content-Type: application/json'
  5. eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwa3Nsb3ciLCJyb2xlcyI6WyJST0xFX0FETUlOIl0sImlhdCI6MTYxMjU5MDYxNCwiZXhwIjoxNjEyNTkxMjE0fQ.d4Gi50aaOsHHqpM0d8Mh1960otnZf7rlE3x6xSfakVo

(3)admin帶JWT訪問/admin,成功;訪問/user失敗

  1. $ curl http://localhost:8080/admin -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwa3Nsb3ciLCJyb2xlcyI6WyJST0xFX0FETUlOIl0sImlhdCI6MTYxMjU5MDYxNCwiZXhwIjoxNjEyNTkxMjE0fQ.d4Gi50aaOsHHqpM0d8Mh1960otnZf7rlE3x6xSfakVo'
  2. you are admin
  3.  
  4. $ curl http://localhost:8080/user -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwa3Nsb3ciLCJyb2xlcyI6WyJST0xFX0FETUlOIl0sImlhdCI6MTYxMjU5MDYxNCwiZXhwIjoxNjEyNTkxMjE0fQ.d4Gi50aaOsHHqpM0d8Mh1960otnZf7rlE3x6xSfakVo'
  5. {"timestamp":"2021-02-06T05:51:23.099+0000","status":403,"error":"Forbidden","message":"Forbidden","path":"/user"}

(4)使用過期的JWT訪問,失敗

  1. $ curl http://localhost:8080/admin -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwa3Nsb3ciLCJyb2xlcyI6WyJST0xFX0FETUlOIl0sImlhdCI6MTYxMjU5MDQ0OSwiZXhwIjoxNjEyNTkwNTA5fQ.CSaubE4iJcYATbLmbb59aNFU1jNCwDFHUV3zIakPU64'
  2. Invalid token

4 總結(jié)

代碼請查看:https://github.com/LarryDpk/pkslow-samples

以上就是Springboot集成Spring Security實(shí)現(xiàn)JWT認(rèn)證的步驟詳解的詳細(xì)內(nèi)容,更多關(guān)于Springboot集成Spring Security的資料請關(guān)注服務(wù)器之家其它相關(guān)文章!

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 国产成人一区二区三区在线观看 | 亚洲国产成人精品女人久久久 | 亚洲国产精品一区二区久久,亚洲午夜 | 日韩精品免费在线视频 | 亚洲一区二区av | 日韩欧美在线综合 | 成人欧美| 午夜久久久久久久 | 成人免费小视频 | 久久久精品天堂 | 一级毛片一级毛片一级毛片 | 亚洲成av人片一区二区梦乃 | 中文字幕在线观看不卡视频 | 81精品国产乱码久久久久久 | 色播一区二区 | 日韩欧美中文字幕在线视频 | 黄色av影视 | 美女88av| av一区二区三区四区 | 久久久久久亚洲精品 | 欧美日一区二区 | 国产精品免费观看 | 免费在线观看黄色 | 国产精品久久久久久久久久久久久 | 亚洲精品久久久久久一区二区 | 久久精品国产精品亚洲 | 热久久影院 | 日本精品在线观看 | 色天堂影院 | 免费骚视频 | 国产一区二区免费 | 亚洲成av在线 | 亚洲a在线观看 | 桃色一区 | 亚洲免费观看 | 免费一区 | 青娱乐国产视频 | 中文字幕在线观看视频地址二 | 亚洲国产精品一区二区三区 | 欧美一区视频 | 中文字幕在线精品 |