SpringBoot集成JWT 實現接口權限認證

JWT介紹

Json web token (JWT), 是爲了在網絡應用環境間傳遞聲明而執行的一種基於JSON的開放標準((RFC 7519).該token被設計爲緊湊且安全的, 特別適用於分佈式站點的單點登陸(`SSO`)場景。JWT的聲明通常被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息, 以便於從資源服務器獲取資源,也能夠增長一些額外的其它業務邏輯所必須的聲明信息,該token也可直接被用於認證,也可被加密。

優勢

  • 體積小、傳輸快
  • 支持跨域受權,由於跨域沒法共享cookie
  • 分佈式系統中,很好地解決了單點登陸問題

缺點

由於JWT是無狀態的,所以服務端沒法控制已經生成的Token失效,是不可控的

使用場景

1. 認證,這是比較常見的使用場景,只要用戶登陸過一次系統,以後的請求都會包含簽名出來的token,經過token也能夠用來實現單點登陸。
2. 交換信息,經過使用密鑰對來安全的傳送信息,能夠知道發送者是誰、放置消息被篡改。


springboot集成JWT過程(注意: 使用了數據庫, 先建表)



項目克隆

項目名稱 springboot-jwt
地址: https://gitee.com/minili/springboot-demo.git
若是以爲該項目對你有幫助或者有疑問的話, 歡迎加星, 評論

添加表

一個是管理員表, 一個是存放token表
在項目下的db文件夾

 1 SET FOREIGN_KEY_CHECKS=0;
 2 
 3 DROP TABLE IF EXISTS `manager`;
 4 CREATE TABLE `manager` (
 5   `managerId` int(5) unsigned NOT NULL AUTO_INCREMENT COMMENT '管理員id',
 6   `managerName` varchar(50) NOT NULL,
 7   `nickName` varchar(50) DEFAULT NULL,
 8   `password` varchar(50) NOT NULL,
 9   `managerLevelId` int(2) NOT NULL,
10   PRIMARY KEY (`managerId`)
11 ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='管理員表';
12 
13 INSERT INTO `manager` VALUES ('1', 'admin', 'admin', '4297f44b13955235245b2497399d7a93', '1');
14 INSERT INTO `manager` VALUES ('2', 'cscscs', 'cscscs', '4297f44b13955235245b2497399d7a93', '1');
15 
16 DROP TABLE IF EXISTS `managertoken`;
17 CREATE TABLE `managertoken` (
18   `managerId` int(20) NOT NULL,
19   `token` varchar(50) NOT NULL,
20   `expireTime` varchar(15) DEFAULT NULL COMMENT '過時時間yyyyMMddHHmmss',
21   `updateTime` varchar(15) DEFAULT NULL COMMENT '更新時間yyyyMMddHHmmss',
22   PRIMARY KEY (`managerId`)
23 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

POM.XML

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4     <modelVersion>4.0.0</modelVersion>
  5     <groupId>com.mycom</groupId>
  6     <artifactId>funfast</artifactId>
  7     <version>0.0.1-SNAPSHOT</version>
  8     <packaging>jar</packaging>
  9 
 10     <name>funfast</name>
 11     <description>project for Spring Boot JWT</description>
 12 
 13     <parent>
 14         <groupId>org.springframework.boot</groupId>
 15         <artifactId>spring-boot-starter-parent</artifactId>
 16         <version>2.0.1.RELEASE</version>
 17         <relativePath/>
 18     </parent>
 19 
 20     <properties>
 21         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 22         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 23         <java.version>1.8</java.version>
 24         <mysql-connector>5.1.38</mysql-connector>
 25         <mybatis-plus-boot-starter.version>2.1.9</mybatis-plus-boot-starter.version>
 26         <druid.version>1.1.10</druid.version>
 27         <fastjson.version>1.2.39</fastjson.version>
 28         <jwt.version>0.7.0</jwt.version>
 29     </properties>
 30 
 31     <dependencies>
 32         <dependency>
 33             <groupId>org.springframework.boot</groupId>
 34             <artifactId>spring-boot-starter</artifactId>
 35             <exclusions>
 36                 <exclusion>
 37                     <groupId>org.springframework.boot</groupId>
 38                     <artifactId>spring-boot-starter-logging</artifactId>
 39                 </exclusion>
 40             </exclusions>
 41         </dependency>
 42 
 43         <!-- Spring Boot web依賴 -->
 44         <dependency>
 45             <groupId>org.springframework.boot</groupId>
 46             <artifactId>spring-boot-starter-web</artifactId>
 47         </dependency>
 48         <!-- log4j2 依賴 -->
 49         <dependency>
 50             <groupId>org.springframework.boot</groupId>
 51             <artifactId>spring-boot-starter-log4j2</artifactId>
 52         </dependency>
 53         <!-- Spring Boot Test 依賴 -->
 54         <dependency>
 55             <groupId>org.springframework.boot</groupId>
 56             <artifactId>spring-boot-starter-test</artifactId>
 57             <scope>test</scope>
 58         </dependency>
 59         <dependency>
 60             <groupId>org.springframework.boot</groupId>
 61             <artifactId>spring-boot-configuration-processor</artifactId>
 62             <optional>true</optional>
 63         </dependency>
 64 
 65         <!-- Spring Boot JDBC 依賴 -->
 66         <dependency>
 67             <groupId>org.springframework.boot</groupId>
 68             <artifactId>spring-boot-starter-jdbc</artifactId>
 69         </dependency>
 70 
 71         <!-- MySQL 鏈接驅動 依賴 -->
 72         <dependency>
 73             <groupId>mysql</groupId>
 74             <artifactId>mysql-connector-java</artifactId>
 75             <version>${mysql-connector}</version>
 76         </dependency>
 77         <!-- druid 鏈接池 依賴 -->
 78         <dependency>
 79             <groupId>com.alibaba</groupId>
 80             <artifactId>druid-spring-boot-starter</artifactId>
 81             <version>${druid.version}</version>
 82         </dependency>
 83 
 84         <!-- shiro 權限控制 -->
 85         <dependency>
 86             <groupId>org.apache.shiro</groupId>
 87             <artifactId>shiro-spring</artifactId>
 88             <version>1.4.0</version>
 89         </dependency>
 90 
 91         <!-- shiro ehcache (shiro緩存)-->
 92         <dependency>
 93             <groupId>org.apache.shiro</groupId>
 94             <artifactId>shiro-ehcache</artifactId>
 95             <version>1.4.0</version>
 96             <exclusions>
 97                 <exclusion>
 98                     <artifactId>slf4j-api</artifactId>
 99                     <groupId>org.slf4j</groupId>
100                 </exclusion>
101             </exclusions>
102         </dependency>
103 
104         <!-- jwt -->
105         <dependency>
106             <groupId>io.jsonwebtoken</groupId>
107             <artifactId>jjwt</artifactId>
108             <version>${jwt.version}</version>
109         </dependency>
110 
111         <!-- fastjson 依賴 -->
112         <dependency>
113             <groupId>com.alibaba</groupId>
114             <artifactId>fastjson</artifactId>
115             <version>${fastjson.version}</version>
116         </dependency>
117 
118     </dependencies>
119 
120     <build>
121         <plugins>
122             <plugin>
123                 <groupId>org.springframework.boot</groupId>
124                 <artifactId>spring-boot-maven-plugin</artifactId>
125             </plugin>
126         </plugins>
127     </build>
128 
129 </project>
pom.xml

修改application.yml文件

 1 # server
 2 server:
 3    tomcat:
 4         uri-encoding: UTF-8
 5         max-threads: 1000
 6         min-spare-threads: 30
 7    port: 8087
 8    servlet:
 9         context-path: /
10 
11 spring:
12     # 環境 dev|prod
13     profiles:
14         active: dev
15 
16     servlet:
17         multipart:
18             max-file-size: 100MB
19             max-request-size: 100MB
20             enabled: true
21 
22     datasource:
23       type: com.alibaba.druid.pool.DruidDataSource
24       driver-class-name: com.mysql.jdbc.Driver
25       druid:
26         url: jdbc:mysql://127.0.0.1:3306/fun-fast?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
27         username: root
28         password: 123123
29 
30         initial-size: 10
31         max-active: 100
32         min-idle: 10
33         max-wait: 60000
34         pool-prepared-statements: true
35         max-pool-prepared-statement-per-connection-size: 20
36         time-between-eviction-runs-millis: 60000
37         min-evictable-idle-time-millis: 300000
38         validation-query: SELECT 1
39         test-while-idle: true
40         test-on-borrow: true
41         test-on-return: false
42         stat-view-servlet:
43           enabled: true
44           url-pattern: /druid/*
45           login-username: admin
46           login-password: 123123
47         filter:
48           stat:
49             log-slow-sql: true
50             slow-sql-millis: 1000
51             merge-sql: false
52           wall:
53             config:
54               multi-statement-allow: true
application.yml

 


主體有5個文件須要添加,分別是shiroConfig、OAuth2Filer配置、OAuth2Realm、OAuth2Token、TokenGenerator java

1. ShiroConfig配置

 1 /**
 2  * Shiro配置
 3  */
 4 @Configuration
 5 public class ShiroConfig {
 6 
 7     @Bean("sessionManager")
 8     public SessionManager sessionManager(){
 9         DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
10         sessionManager.setSessionValidationSchedulerEnabled(true);
11         sessionManager.setSessionIdCookieEnabled(true);
12         return sessionManager;
13     }
14 
15     @Bean("securityManager")
16     public SecurityManager securityManager(OAuth2Realm oAuth2Realm, SessionManager sessionManager) {
17         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
18         securityManager.setRealm(oAuth2Realm);
19         securityManager.setSessionManager(sessionManager);
20 
21         return securityManager;
22     }
23 
24     @Bean("shiroFilter")
25     public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
26         ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
27         shiroFilter.setSecurityManager(securityManager);
28 
29         //oauth過濾
30         Map<String, Filter> filters = new HashMap<>();
31         filters.put("oauth2", new OAuth2Filter());
32         shiroFilter.setFilters(filters);
33 
34         Map<String, String> filterMap = new LinkedHashMap<>();
35         filterMap.put("/druid/**", "anon");
36         filterMap.put("/app/**", "anon");
37         filterMap.put("/login", "anon");
38         filterMap.put("/**", "oauth2");
39         shiroFilter.setFilterChainDefinitionMap(filterMap);
40 
41         return shiroFilter;
42     }
43 
44     @Bean("lifecycleBeanPostProcessor")
45     public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
46         return new LifecycleBeanPostProcessor();
47     }
48 
49     @Bean
50     public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
51         DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
52         proxyCreator.setProxyTargetClass(true);
53         return proxyCreator;
54     }
55 
56     @Bean
57     public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
58         AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
59         advisor.setSecurityManager(securityManager);
60         return advisor;
61     }
62 
63 }

 

2. OAuth2Filer配置

這個裏面能夠配置權限過濾的規則mysql

 1 /**
 2  * oauth2過濾器
 3  */
 4 public class OAuth2Filter extends AuthenticatingFilter {
 5 
 6     @Override
 7     protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
 8         //獲取請求token
 9         String token = getRequestToken((HttpServletRequest) request);
10 
11         if(StringUtil.isBlank(token)){
12             return null;
13         }
14 
15         return new OAuth2Token(token);
16     }
17 
18     @Override
19     protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
20         if(((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())){
21             return true;
22         }
23 
24         return false;
25     }
26 
27     @Override
28     protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
29         //獲取請求token,若是token不存在,直接返回401
30         HttpServletRequest httpServletRequest = (HttpServletRequest) request;
31         String token = getRequestToken((HttpServletRequest) request);
32         if(StringUtil.isBlank(token)){
33             HttpServletResponse httpResponse = (HttpServletResponse) response;
34             httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
35             httpResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin"));
36 
37             JSONObject json = new JSONObject();
38             json.put("code", "401");
39             json.put("msg", "invalid token");
40 
41             httpResponse.getWriter().print(json);
42 
43             return false;
44         }
45 
46         return executeLogin(request, response);
47     }
48 
49     @Override
50     protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
51         HttpServletResponse httpResponse = (HttpServletResponse) response;
52         HttpServletRequest httpServletRequest = (HttpServletRequest) request;
53         httpResponse.setContentType("application/json;charset=utf-8");
54         httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
55         httpResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin"));
56         try {
57             //處理登陸失敗的異常
58             Throwable throwable = e.getCause() == null ? e : e.getCause();
59 
60             JSONObject json = new JSONObject();
61             json.put("code", "401");
62             json.put("msg", throwable.getMessage());
63 
64             httpResponse.getWriter().print(json);
65         } catch (IOException e1) {
66 
67         }
68 
69         return false;
70     }
71 
72     /**
73      * 獲取請求的token
74      */
75     private String getRequestToken(HttpServletRequest httpRequest){
76         //從header中獲取token
77         String token = httpRequest.getHeader("token");
78 
79         //若是header中不存在token,則從參數中獲取token
80         if(StringUtil.isBlank(token)){
81             token = httpRequest.getParameter("token");
82         }
83 
84         return token;
85     }
86 }
OAuth2Filer

3. OAuth2Realm配置

這個裏面能夠設置角色、權限和認證信息git

 1 /**
 2  * 認證
 3  */
 4 @Component
 5 public class OAuth2Realm extends AuthorizingRealm {
 6     @Autowired
 7     private ManagerService managerService;
 8 
 9     @Override
10     public boolean supports(AuthenticationToken token) {
11         return token instanceof OAuth2Token;
12     }
13 
14     /**
15      * 受權(驗證權限時調用, 控制role 和 permissins時使用)
16      */
17     @Override
18     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
19         ManagerInfo manager = (ManagerInfo)principals.getPrimaryPrincipal();
20         Integer managerId = manager.getManagerId();
21 
22         SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
23 
24         // 模擬權限和角色
25         Set<String> permsSet = new HashSet<>();
26         Set<String> roles = new HashSet<>();
27         if (managerId == 1) {
28             // 超級管理員-權限
29             permsSet.add("delete");
30             permsSet.add("update");
31             permsSet.add("view");
32 
33             roles.add("admin");
34         } else {
35             // 普通管理員-權限
36             permsSet.add("view");
37 
38             roles.add("test");
39         }
40 
41         info.setStringPermissions(permsSet);
42         info.setRoles(roles);
43 
44         return info;
45     }
46 
47     /**
48      * 認證(登陸時調用)
49      */
50     @Override
51     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
52         String accessToken = (String) token.getPrincipal();
53 
54         //根據accessToken,查詢用戶信息
55         ManagerToken managerToken = managerService.queryByToken(accessToken);
56         //token失效
57         SimpleDateFormat sm = new SimpleDateFormat("yyyyMMddHHmmss");
58         Date expireTime;
59         boolean flag = true;
60         try {
61             expireTime     = sm.parse(managerToken.getExpireTime());
62             flag = managerToken == null || expireTime.getTime() < System.currentTimeMillis();
63         } catch (ParseException e) {
64             e.printStackTrace();
65         }
66 
67         if(flag){
68             throw new IncorrectCredentialsException("token失效,請從新登陸");
69         }
70 
71         //查詢用戶信息
72         ManagerInfo managerInfo = managerService.getManagerInfo(managerToken.managerId);
73         //帳號鎖定
74         // if(managerInfo.getStatus() == 0){
75         //     throw new LockedAccountException("帳號已被鎖定,請聯繫管理員");
76         // }
77 
78         SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(managerInfo, accessToken, getName());
79 
80         return info;
81     }
82 }
OAuth2Realm

4. OAuth2Token設置

 1 /**
 2  * token
 3  */
 4 public class OAuth2Token implements AuthenticationToken {
 5     private String token;
 6 
 7     public OAuth2Token(String token){
 8         this.token = token;
 9     }
10 
11     @Override
12     public String getPrincipal() {
13         return token;
14     }
15 
16     @Override
17     public Object getCredentials() {
18         return token;
19     }
20 }
View Code

5. TokenGenerator, 生成token

 1 /**
 2  * 生成token
 3  */
 4 public class TokenGenerator {
 5 
 6     public static String generateValue() {
 7         return generateValue(UUID.randomUUID().toString());
 8     }
 9 
10     private static final char[] hexCode = "0123456789abcdef".toCharArray();
11 
12     public static String toHexString(byte[] data) {
13         if (data == null) {
14             return null;
15         }
16         StringBuilder r = new StringBuilder(data.length * 2);
17         for (byte b : data) {
18             r.append(hexCode[(b >> 4) & 0xF]);
19             r.append(hexCode[(b & 0xF)]);
20         }
21         return r.toString();
22     }
23 
24     public static String generateValue(String param) {
25         try {
26             MessageDigest algorithm = MessageDigest.getInstance("MD5");
27             algorithm.reset();
28             algorithm.update(param.getBytes());
29             byte[] messageDigest = algorithm.digest();
30             return toHexString(messageDigest);
31         } catch (Exception e) {
32             throw new RuntimeException("生成Token失敗", e);
33         }
34     }
35 }
View Code

 

Controller

@RestController
public class WebController {

    private static final Logger LOGGER = LogManager.getLogger(WebController.class);

    @Autowired
    private ManagerService managerService;

    @RequestMapping("/login")
    public JSONObject login(@RequestParam("username") String username,
                            @RequestParam("password") String password) {
        JSONObject json = new JSONObject();
        json.put("result", false);
        json.put("msg", "帳號或密碼不正確");

        // 用戶信息
        ManagerInfo managerInfo = managerService.getManagerInfo(username);
        // 帳號不存在、密碼錯誤
        if (managerInfo == null || !managerInfo.getPassword().equals(password)) {
            return json;
        }

        ManagerToken managerToken = managerService.saveToken(managerInfo.managerId);
        json.put("token", managerToken.token);
        json.put("result", true);
        json.put("msg", "登錄成功");

        return json;
    }

    /**
     * 必須帶token請求, 不然返回401
     */
    @GetMapping("/article")
    public BaseResponse article() {
        return new BaseResponse(true, "article: You are already logged in", null);
    }

    /**
     * 沒必要帶token也能請求到內容, 由於在shiro中配置了過濾規則
     */
    @GetMapping("/app/article")
    public BaseResponse appArticle() {
        return new BaseResponse(true, "appArticle: You are already logged in", null);
    }

    /**
     * 須要是超級管理員的token才能查看,
     */
    @GetMapping("/require_role")
    @RequiresRoles("admin")
    public BaseResponse requireRole() {
        return new BaseResponse(true, "You are visiting require_role", null);
    }

    /**
     * 須要有update權限才能訪問
     */
    @GetMapping("/require_permission")
    // @RequiresPermissions(logical = Logical.AND, value = {"view", "edit"})
    @RequiresPermissions(logical = Logical.AND, value = {"update"})
    public BaseResponse requirePermission() {
        return new BaseResponse(true, "You are visiting permission require update", null);
    }

}

 

Service

 1 @Service
 2 public class ManagerService extends AbstractService {
 3     //12小時後過時
 4     private final static int EXPIRE = 3600 * 12 * 1000;
 5 
 6     public ManagerInfo getManagerInfo(String managerName) {
 7         String sql = "select a.managerName, a.managerLevelId,a.managerId, a.password"
 8                 + " from manager a where a.managerName=?";
 9         ManagerInfo manager = jdbcDao.queryForObject(sql, new Object[] { managerName }, ManagerInfo.class);
10 
11         return manager;
12     }
13 
14     public ManagerToken saveToken(Integer managerId) {
15         ManagerToken managerToken = new ManagerToken();
16         managerToken.managerId = managerId;
17 
18         //生成一個token
19         managerToken.token = TokenGenerator.generateValue();
20         //過時時間
21         Date expireTime = new Date(System.currentTimeMillis() + EXPIRE);
22 
23         // 更新時間/過時時間
24         SimpleDateFormat sm = new SimpleDateFormat("yyyyMMddHHmmss");
25         Date systemDate = new Date();
26         managerToken.updateTime = sm.format(systemDate);
27         managerToken.expireTime = sm.format(expireTime);
28 
29         String sql = "insert into managertoken (managerId, token, updateTime, expireTime) values (?,?,?,?)"
30                 + " ON DUPLICATE KEY UPDATE token=?, updateTime=?, expireTime=?";
31         jdbcDao.update(sql, new Object[]{managerToken.managerId, managerToken.token, managerToken.updateTime,
32                 managerToken.expireTime, managerToken.token, managerToken.updateTime, managerToken.expireTime});
33 
34         return managerToken;
35     }
36 
37     @Transactional(propagation= Propagation.REQUIRED, isolation= Isolation.DEFAULT, readOnly = true, rollbackFor = Exception.class)
38     public ManagerInfo getManagerInfo(Integer managerId) {
39         if (managerId == null) {
40             return null;
41         }
42 
43         String sql = "select a.managerId, a.managerName, a.managerLevelId from manager a " +
44                 "where a.managerId=?";
45         ManagerInfo manager = jdbcDao.queryForObject(sql, new Object[]{managerId}, ManagerInfo.class);
46 
47         return manager;
48     }
49 
50     public ManagerToken queryByToken(String token) {
51         if (token == null || "".equals(token)) {
52             return null;
53         }
54 
55         String sql = "select managerid managerId, token, expireTime, updateTime from managertoken where token=?";
56         ManagerToken managerToken = jdbcDao.queryForObject(sql, new Object[]{token}, ManagerToken.class);
57 
58         return managerToken;
59     }
60 
61 }
service

 

這裏省略了一些基礎的實體類、工具類,詳見代碼web


登錄測試

先登錄獲取到token(localhost:8087/login?username=cscscs&password=4297f44b13955235245b2497399d7a93)
這裏測試的用戶有兩個一個admin(超級管理員), 一個是cscscs

 

測試須要認證的接口

 1.不帶token訪問spring

 

 2.帶token訪問sql

注意是headers中添加參數token數據庫

 

測試不須要認證的接口

在OAuth2Filter中我對,/app 路徑下的接口不須要認證apache

測試角色認證的接口

/require_role, 這個接口須要admin角色才能訪問,在OAuth2Realm中我設置了admin用戶爲超級管理員角色, cscscs用戶爲test角色json

1. cscscs用戶訪問(選擇cscscs用戶的token)api

2.admin用戶訪問(選擇admin用戶的token)

測試權限認證的接口

平時咱們能夠設置管理員是否有刪除,更新記錄的權限

/require_permission在控制器中設置了只有擁有update權限的用戶才能訪問, 在OAuth2Realm中我給了admin用戶update的權限, 給了cscscs用戶view的權限

1.使用cscscs用戶的token訪問

 

2. 使用admin用戶訪問

 

結語

1. 但願能給本身幫助、也給別人幫助,有任何疑問或者意見,在下方留言哦

2, 有不少不足能夠改進, 如緩存啊, 更準確的權限設置啊, 但他能夠幫你構建一個完整可用的JWT

   以前看了網上的例子, 理論很好, 例子卻沒跑通, aaaaa,,,

相關文章
相關標籤/搜索