86183
2022-09-09 0d999e33085c0a25c5525242748f6aa62a401159
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
 
 
package cn.mb.cloud.auth.endpoint;
 
import cn.hutool.core.util.StrUtil;
import cn.mb.cloud.auth.security.component.MbCloudAuthUser;
import cn.mb.cloud.common.cache.RedisFastJsonTemplate;
import cn.mb.cloud.common.core.constant.SecurityConstants;
import cn.mb.cloud.common.core.util.ResponseData;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.ConvertingCursor;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.HttpHeaders;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
 
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
 
/**
 * @author jason
 * 删除token端点
 */
@RestController
@AllArgsConstructor
@RequestMapping("/token")
public class CloudTokenEndpoint {
    private static final String OAUTH_ACCESS_KEY_PREFIX = "oauth2_auth_to_access:";
    private final TokenStore tokenStore;
    private final RedisFastJsonTemplate redisTemplate;
    private final CacheManager cacheManager;
 
    /**
     * 认证页面
     *
     * @return ModelAndView
     */
    @GetMapping("/login")
    public ModelAndView require() {
        return new ModelAndView("ftl/login");
    }
 
    /**
     * 退出token
     *
     * @param authHeader Authorization
     */
    @PostMapping("/logout")
    public ResponseData logout(@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader, HttpServletRequest request) {
        if (StrUtil.isBlank(authHeader)) {
            return ResponseData.fail("退出失败,token 为空");
        }
 
        String tokenValue = authHeader.replace(OAuth2AccessToken.BEARER_TYPE, StrUtil.EMPTY).trim();
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
        if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
            return ResponseData.fail("退出失败,token 无效");
        }
 
        OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
        cacheManager.getCache("user_details").evict(auth2Authentication.getName());
        tokenStore.removeAccessToken(accessToken);
        return ResponseData.success(Boolean.TRUE);
    }
 
    /**
     * 获取用户的授权码
     *
     * @param authHeader
     * @return
     */
    @GetMapping("user/permissions")
    public ResponseData findUserPermissionKey(@RequestHeader(value = HttpHeaders.AUTHORIZATION,
            required = false) String authHeader) {
 
        if (StrUtil.isBlank(authHeader)) {
            return ResponseData.fail("token 为空");
        }
 
        String tokenValue = authHeader.replace(OAuth2AccessToken.BEARER_TYPE, StrUtil.EMPTY).trim();
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
        if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
            return ResponseData.fail("token 无效");
        }
 
        OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
        MbCloudAuthUser mbCloudAuthUser = (MbCloudAuthUser) auth2Authentication.getPrincipal();
 
        HashSet<String> permissions = (HashSet<String>) redisTemplate.opsForValue().
                get(SecurityConstants.CACHE_USER_PERMISSIONS_KEY + "key:" + mbCloudAuthUser.getId());
        return ResponseData.success(permissions);
    }
 
 
    /**
     * 令牌管理调用
     *
     * @param token token
     * @return
     */
    @GetMapping("del/{token}")
    public ResponseData<Boolean> delToken(@PathVariable("token") String token) {
        OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
        tokenStore.removeAccessToken(oAuth2AccessToken);
        return ResponseData.success();
    }
 
 
    /**
     * 查询token
     *
     * @param page 分页参数
     * @return
     */
    @GetMapping("/page")
    public ResponseData<Page> tokenList(Page page) {
        //根据分页参数获取对应数据
        String key = String.format("%s*", OAUTH_ACCESS_KEY_PREFIX);
        List<String> pages = findKeysForPage(key, page.getCurrent(), page.getSize());
 
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        page.setRecords(redisTemplate.opsForValue().multiGet(pages));
        page.setTotal(Long.valueOf(redisTemplate.keys(key).size()));
        return ResponseData.success(page);
    }
 
 
    private List<String> findKeysForPage(String patternKey, Long pageNum, Long pageSize) {
        ScanOptions options = ScanOptions.scanOptions().match(patternKey).build();
        RedisSerializer<String> redisSerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
        Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection
                (redisConnection -> new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize));
        List<String> result = new ArrayList<>();
        int tmpIndex = 0;
        long startIndex = (pageNum - 1) * pageSize;
        long end = pageNum * pageSize;
 
        assert cursor != null;
        while (cursor.hasNext()) {
            if (tmpIndex >= startIndex && tmpIndex < end) {
                result.add(cursor.next().toString());
                tmpIndex++;
                continue;
            }
            if (tmpIndex >= end) {
                break;
            }
            tmpIndex++;
            cursor.next();
        }
        return result;
    }
 
 
}