更多最新技術文章歡迎大家通路我的個人部落格○( ^皿^)っ豆腐别館
上文總覽篇中,相信大家已經對接下來要做的事情有了總體思路及印象。總言之我們要做的就隻有兩件事,一是授權,二即是鑒權。
讓我們先從授權開始,何為授權?在這裡簡單地來講就是要頒發token。何時頒發?毫無疑問,無非就是在登入/注冊成功之後。至于上文中提到的根據RefreshToken自動重新整理AccessToken,我将之歸置為token重新整理,代碼實作于後續篇章說明。
一、Maven配置
com.auth0
java-jwt
${java-jwt.version}
二、Application配置
server:
port: 8001
spring:
application:
name: springboot-shiro-jwt-sso
# profiles: springboot-shiro-jwt-sso
## Redis配置 - start
redis:
# Redis資料庫索引(預設為0)
database: 1
# Redis伺服器位址
host: 127.0.0.1
# Redis伺服器連接配接端口
port: 6379
# Redis伺服器連接配接密碼(預設為空)
# password: "doufuplus"
# 連接配接逾時時間(毫秒)
timeout: 5000
jedis:
pool:
# 連接配接池最大連接配接數(使用負值表示沒有限制)
max-active: 8
# 連接配接池最大阻塞等待時間(使用負值表示沒有限制)
max-wait: -1
# 連接配接池中的最大空閑連接配接
max-idle: 8
# 連接配接池中的最小空閑連接配接
min-idle: 0
## Redis配置 - end
## 時間格式配置 - start
jackson:
serialization:
write-dates-as-timestamps: true
## 時間格式配置 - end
## product配置 - start
info:
app.name: springboot-shiro-jwt-sso
company.name: doufuplus
build.artifactId: $project.artifactId$
build.modelVersion: $project.modelVersion$
## product配置 - end
## 日志配置 - start
logging:
level:
com.nfgj.medical.service: DEBUG
## 日志配置 - end
## 其它配置 - start
config:
# JWT認證加密私鑰(Base64加密)
encrypt-jwtKey: U0JBUElOENhspJrzkyNjQ1NA
# AccessToken過期時間(秒)
accessToken-expireTime: 600
# RefreshToken過期時間(秒)
refreshToken-expireTime: 604800
## 其它配置 - end
三、頒發Token
token的頒發并未有什麼難度,主要是生成AccessToken放置于Header給前端。再生成RefreshToken儲存于服務端即可。此處使用redis儲存。
@PostMapping("/login")
public Result login(String account, String password, HttpServletResponse response) {
try {
if (!("doufuplus".equals(account) && "123456".equals(password))) {
return new Result(ResultCode.PASSWORD_ERROR, "account or password error.");
}
// 清除可能存在的shiro權限資訊緩存
if (redis.hasKey(RedisConstant.PREFIX_SHIRO_CACHE + account)) {
redis.del(RedisConstant.PREFIX_SHIRO_CACHE + account);
}
// 設定RefreshToken,時間戳為目前時間戳,直接設定即可(不用先删後設,會覆寫已有的RefreshToken)
String currentTimeMillis = String.valueOf(System.currentTimeMillis());
redis.set(RedisConstant.PREFIX_SHIRO_REFRESH_TOKEN + account, currentTimeMillis,
Integer.parseInt(refreshTokenExpireTime));
// 從Header中Authorization傳回AccessToken,時間戳為目前時間戳
String token = JwtUtil.sign(account, currentTimeMillis);
response.setHeader("Authorization", token);
response.setHeader("Access-Control-Expose-Headers", "Authorization");
return new Result().OK();
} catch (Exception e) {
e.printStackTrace();
return new Result(ResultCode.ERROR, e.getMessage());
}
}
四、清除Token
沒有買賣就沒有傷害,有登入就會有退出。token的清除主要是做兩件事:
清除可能存在的shiro權限資訊
清除RefreshToken
@RequestMapping("/logout")
public Result logout() {
try {
String token = "";
// 擷取頭部資訊
Enumeration headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
String value = request.getHeader(key);
if ("Authorization".equalsIgnoreCase(key)) {
token = value;
}
}
// 校驗token
if (StringUtils.isBlank(token)) {
return new Result(ResultCode.PARAM_ERROR);
}
String account = JwtUtil.getClaim(token, JwtConstant.ACCOUNT);
if (StringUtils.isBlank(account)) {
return new Result(ResultCode.NOT_LOGIN, "token失效或不正确.");
}
// 清除shiro權限資訊緩存
if (redis.hasKey(RedisConstant.PREFIX_SHIRO_CACHE + account)) {
redis.del(RedisConstant.PREFIX_SHIRO_CACHE + account);
}
// 清除RefreshToken
redis.del(RedisConstant.PREFIX_SHIRO_REFRESH_TOKEN + account);
return new Result().OK();
} catch (Exception e) {
e.printStackTrace();
return new Result(ResultCode.ERROR, e.getMessage());
}
}
五、示範說明
登入成功,傳回10200

登入成功-1.png
檢視Header,Authorization傳回AccessToken資訊

登入成功-2.png