最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Boot Security 結(jié)合 JWT 實現(xiàn)無狀態(tài)的分布式API接口

 更新時間:2019年04月01日 10:51:24   作者:幻楚  
JSON Web Token(縮寫 JWT)是目前最流行的跨域認(rèn)證解決方案。這篇文章主要介紹了Spring Boot Security 結(jié)合 JWT 實現(xiàn)無狀態(tài)的分布式API接口 ,需要的朋友可以參考下

簡介

JSON Web Token(縮寫 JWT)是目前最流行的跨域認(rèn)證解決方案。JSON Web Token 入門教程 這篇文章可以幫你了解JWT的概念。本文重點講解Spring Boot 結(jié)合 jwt ,來實現(xiàn)前后端分離中,接口的安全調(diào)用。

Spring Security,這是一種基于 Spring AOP 和 Servlet 過濾器的安全框架。它提供全面的安全性解決方案,同時在 Web 請求級和方法調(diào)用級處理身份確認(rèn)和授權(quán)。

快速上手

之前的文章已經(jīng)對 Spring Security 進(jìn)行了講解,這一節(jié)對涉及到 Spring Security 的配置不詳細(xì)講解。若不了解 Spring Security 先移步到 Spring Boot Security 詳解。

建表

DROP TABLE IF EXISTS `user`;
DROP TABLE IF EXISTS `role`;
DROP TABLE IF EXISTS `user_role`;
DROP TABLE IF EXISTS `role_permission`;
DROP TABLE IF EXISTS `permission`;

CREATE TABLE `user` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`) 
);
CREATE TABLE `role` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`) 
);
CREATE TABLE `user_role` (
`user_id` bigint(11) NOT NULL,
`role_id` bigint(11) NOT NULL
);
CREATE TABLE `role_permission` (
`role_id` bigint(11) NOT NULL,
`permission_id` bigint(11) NOT NULL
);
CREATE TABLE `permission` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`url` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
`description` varchar(255) NULL,
`pid` bigint(11) NOT NULL,
PRIMARY KEY (`id`) 
);

INSERT INTO user (id, username, password) VALUES (1,'user','e10adc3949ba59abbe56e057f20f883e'); 
INSERT INTO user (id, username , password) VALUES (2,'admin','e10adc3949ba59abbe56e057f20f883e'); 
INSERT INTO role (id, name) VALUES (1,'USER');
INSERT INTO role (id, name) VALUES (2,'ADMIN');
INSERT INTO permission (id, url, name, pid) VALUES (1,'/user/hi','',0);
INSERT INTO permission (id, url, name, pid) VALUES (2,'/admin/hi','',0);
INSERT INTO user_role (user_id, role_id) VALUES (1, 1);
INSERT INTO user_role (user_id, role_id) VALUES (2, 1);
INSERT INTO user_role (user_id, role_id) VALUES (2, 2);
INSERT INTO role_permission (role_id, permission_id) VALUES (1, 1);
INSERT INTO role_permission (role_id, permission_id) VALUES (2, 1);
INSERT INTO role_permission (role_id, permission_id) VALUES (2, 2);

項目結(jié)構(gòu)

resources
|___application.yml
java
|___com
| |____gf
| | |____SpringbootJwtApplication.java
| | |____config
| | | |____.DS_Store
| | | |____SecurityConfig.java
| | | |____MyFilterSecurityInterceptor.java
| | | |____MyInvocationSecurityMetadataSourceService.java
| | | |____MyAccessDecisionManager.java
| | |____entity
| | | |____User.java
| | | |____RolePermisson.java
| | | |____Role.java
| | |____mapper
| | | |____PermissionMapper.java
| | | |____UserMapper.java
| | | |____RoleMapper.java
| | |____utils
| | | |____JwtTokenUtil.java
| | |____controller
| | | |____AuthController.java
| | |____filter
| | | |____JwtTokenFilter.java
| | |____service
| | | |____impl
| | | | |____AuthServiceImpl.java
| | | | |____UserDetailsServiceImpl.java
| | | |____AuthService.java

關(guān)鍵代碼

pom.xml

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
 <groupId>io.jsonwebtoken</groupId>
 <artifactId>jjwt</artifactId>
 <version>0.9.0</version>
</dependency>
<dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <scope>runtime</scope>
</dependency>
<dependency>
 <groupId>org.mybatis.spring.boot</groupId>
 <artifactId>mybatis-spring-boot-starter</artifactId>
 <version>2.0.0</version>
</dependency>

application.yml

spring:
 datasource:
 driver-class-name: com.mysql.cj.jdbc.Driver
 url: jdbc:mysql://localhost:3306/spring-security-jwt?useUnicode=true&characterEncoding=utf-8&useSSL=false
 username: root
 password: root
SecurityConfig
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 @Autowired
 private UserDetailsService userDetailsService;
 @Autowired
 public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
 //校驗用戶
 auth.userDetailsService( userDetailsService ).passwordEncoder( new PasswordEncoder() {
  //對密碼進(jìn)行加密
  @Override
  public String encode(CharSequence charSequence) {
  System.out.println(charSequence.toString());
  return DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
  }
  //對密碼進(jìn)行判斷匹配
  @Override
  public boolean matches(CharSequence charSequence, String s) {
  String encode = DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
  boolean res = s.equals( encode );
  return res;
  }
 } );
 }
 @Override
 protected void configure(HttpSecurity http) throws Exception {
 http.csrf().disable()
  //因為使用JWT,所以不需要HttpSession
  .sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS).and()
  .authorizeRequests()
  //OPTIONS請求全部放行
  .antMatchers( HttpMethod.OPTIONS, "/**").permitAll()
  //登錄接口放行
  .antMatchers("/auth/login").permitAll()
  //其他接口全部接受驗證
  .anyRequest().authenticated();
 //使用自定義的 Token過濾器 驗證請求的Token是否合法
 http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
 http.headers().cacheControl();
 }
 @Bean
 public JwtTokenFilter authenticationTokenFilterBean() throws Exception {
 return new JwtTokenFilter();
 }
 @Bean
 @Override
 public AuthenticationManager authenticationManagerBean() throws Exception {
 return super.authenticationManagerBean();
 }
}

JwtTokenUtil

/**
 * JWT 工具類
 */
@Component
public class JwtTokenUtil implements Serializable {
 private static final String CLAIM_KEY_USERNAME = "sub";
 /**
 * 5天(毫秒)
 */
 private static final long EXPIRATION_TIME = 432000000;
 /**
 * JWT密碼
 */
 private static final String SECRET = "secret";
 /**
 * 簽發(fā)JWT
 */
 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();
 }
 /**
 * 驗證JWT
 */
 public Boolean validateToken(String token, UserDetails userDetails) {
 User user = (User) userDetails;
 String username = getUsernameFromToken( token );
 return (username.equals( user.getUsername() ) && !isTokenExpired( token ));
 }
 /**
 * 獲取token是否過期
 */
 public Boolean isTokenExpired(String token) {
 Date expiration = getExpirationDateFromToken( token );
 return expiration.before( new Date() );
 }
 /**
 * 根據(jù)token獲取username
 */
 public String getUsernameFromToken(String token) {
 String username = getClaimsFromToken( token ).getSubject();
 return username;
 }
 /**
 * 獲取token的過期時間
 */
 public Date getExpirationDateFromToken(String token) {
 Date expiration = getClaimsFromToken( token ).getExpiration();
 return expiration;
 }
 /**
 * 解析JWT
 */
 private Claims getClaimsFromToken(String token) {
 Claims claims = Jwts.parser()
  .setSigningKey( SECRET )
  .parseClaimsJws( token )
  .getBody();
 return claims;
 }
}

JwtTokenFilter

@Component
public class JwtTokenFilter extends OncePerRequestFilter {
 @Autowired
 private UserDetailsService userDetailsService;
 @Autowired
 private JwtTokenUtil jwtTokenUtil;
 /**
 * 存放Token的Header Key
 */
 public static final String HEADER_STRING = "Authorization";
 @Override
 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
 String token = request.getHeader( HEADER_STRING );
 if (null != token) {
  String username = jwtTokenUtil.getUsernameFromToken(token);
  if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
  UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
  if (jwtTokenUtil.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);
 }
}

AuthServiceImpl

@Service
public class AuthServiceImpl implements AuthService {
 @Autowired
 private AuthenticationManager authenticationManager;
 @Autowired
 private UserDetailsService userDetailsService;
 @Autowired
 private JwtTokenUtil jwtTokenUtil;
 @Override
 public String login(String username, String password) {
 UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken( username, password );
 Authentication authentication = authenticationManager.authenticate(upToken);
 SecurityContextHolder.getContext().setAuthentication(authentication);
 UserDetails userDetails = userDetailsService.loadUserByUsername( username );
 String token = jwtTokenUtil.generateToken(userDetails);
 return token;
 }
}

關(guān)鍵代碼就是這些,其他類代碼參照后面提供的源碼地址。

驗證

登錄,獲取token

curl -X POST -d "username=admin&password=123456" http://127.0.0.1:8080/auth/login

返回

eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTU1NDQ1MzUwMX0.sglVeqnDGUL9pH1oP3Lh9XrdzJIS42VKBApd2nPJt7e1TKhCEY7AUfIXnzG9vc885_jTq4-h8R6YCtRRJzl8fQ

不帶token訪問資源

curl -X POST -d "name=zhangsan" http://127.0.0.1:8080/admin/hi

返回,拒絕訪問

{
 "timestamp": "2019-03-31T08:50:55.894+0000",
 "status": 403,
 "error": "Forbidden",
 "message": "Access Denied",
 "path": "/auth/login"
}

攜帶token訪問資源

curl -X POST -H "Authorization: eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTU1NDQ1MzUwMX0.sglVeqnDGUL9pH1oP3Lh9XrdzJIS42VKBApd2nPJt7e1TKhCEY7AUfIXnzG9vc885_jTq4-h8R6YCtRRJzl8fQ" -d "name=zhangsan" http://127.0.0.1:8080/admin/hi

返回正確

hi zhangsan , you have 'admin' role

源碼

https://github.com/gf-huanchupk/SpringBootLearning/tree/master/springboot-jwt

總結(jié)

以上所述是小編給大家介紹的Spring Boot Security 結(jié)合 JWT 實現(xiàn)無狀態(tài)的分布式API接口,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Spring動態(tài)配置計時器觸發(fā)時間的實例代碼

    Spring動態(tài)配置計時器觸發(fā)時間的實例代碼

    這篇文章主要介紹了Spring動態(tài)配置計時器觸發(fā)時間的實例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-06-06
  • windows命令行中java和javac、javap使用詳解(java編譯命令)

    windows命令行中java和javac、javap使用詳解(java編譯命令)

    最近重新復(fù)習(xí)了一下java基礎(chǔ),這里便講講對于一個類文件如何編譯、運(yùn)行、反編譯的。也讓自己加深一下印象
    2014-03-03
  • IDEA的Terminal無法執(zhí)行g(shù)it命令問題

    IDEA的Terminal無法執(zhí)行g(shù)it命令問題

    這篇文章主要介紹了IDEA的Terminal無法執(zhí)行g(shù)it命令問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • mybatis-plus QueryWrapper自定義查詢條件的實現(xiàn)

    mybatis-plus QueryWrapper自定義查詢條件的實現(xiàn)

    這篇文章主要介紹了mybatis-plus QueryWrapper自定義查詢條件的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • RocketMQ集群消費與廣播消費模式

    RocketMQ集群消費與廣播消費模式

    這篇文章主要介紹了RocketMQ集群消費與廣播消費模式,消息隊列RocketMQ版支持集群消費和廣播消費,本文介紹集群消費和廣播消費的基本概念、適用場景、功能差異、注意事項以及設(shè)置方式
    2023-02-02
  • 利用Spring?boot+LogBack+MDC實現(xiàn)鏈路追蹤

    利用Spring?boot+LogBack+MDC實現(xiàn)鏈路追蹤

    這篇文章主要介紹了利用Spring?boot+LogBack+MDC實現(xiàn)鏈路追蹤,MDC?可以看成是一個與當(dāng)前線程綁定的哈希表,可以往其中添加鍵值對,下文詳細(xì)介紹需要的小伙伴可以參考一下
    2022-04-04
  • SpringBoot中@Conditional注解的使用

    SpringBoot中@Conditional注解的使用

    這篇文章主要介紹了SpringBoot中@Conditional注解的使用,@Conditional注解是一個條件裝配注解,主要用于限制@Bean注解在什么時候才生效,以指定的條件形式控制bean的創(chuàng)建,需要的朋友可以參考下
    2024-01-01
  • Feign遠(yuǎn)程調(diào)用丟失請求頭問題

    Feign遠(yuǎn)程調(diào)用丟失請求頭問題

    本文介紹了在服務(wù)端項目中如何解決資源訪問限制問題,首先介紹了問題的產(chǎn)生,然后詳細(xì)解析了源碼,最后提出了解決方案,解決方案包括同步和異步兩種,同步時直接向Spring容器注入RequestInterceptor攔截器
    2024-09-09
  • 使用Idea簡單快速搭建springcloud項目的圖文教程

    使用Idea簡單快速搭建springcloud項目的圖文教程

    這篇文章主要介紹了使用Idea簡單快速搭建springcloud項目,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • springboot中Getmapping獲取參數(shù)的實現(xiàn)方式

    springboot中Getmapping獲取參數(shù)的實現(xiàn)方式

    這篇文章主要介紹了springboot中Getmapping獲取參數(shù)的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05

最新評論

开封市| 谢通门县| 城固县| 平乐县| 酒泉市| 休宁县| 龙里县| 岫岩| 琼海市| 莲花县| 珠海市| 望奎县| 民和| 石狮市| 肇庆市| 东城区| 宁蒗| 长沙县| 定陶县| 乌兰县| 阿拉善左旗| 赣榆县| 沁水县| 东乡| 石林| 吴忠市| 广东省| 广汉市| 万山特区| 沾化县| 高淳县| 同心县| 始兴县| 奉贤区| 科尔| 福泉市| 遂昌县| 中西区| 青铜峡市| 夹江县| 蒙城县|