您好,登錄后才能下訂單哦!
本篇文章將講述Spring Security 簡(jiǎn)單整合JWT 處理認(rèn)證授權(quán)
有關(guān)JWT
不了解的可以看下官網(wǎng)文檔:https://jwt.io/introduction/
<!-- jwt依賴(lài): https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
jwt生成令牌代碼如下:
// 生成jwt訪(fǎng)問(wèn)令牌
String jwtToken = Jwts.builder()
// 用戶(hù)角色
.claim("ROLE_LOGIN", "ADMIN")
// 主題 - 存用戶(hù)名
.setSubject("張三")
// 過(guò)期時(shí)間 - 30分鐘
.setExpiration(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
// 加密算法和密鑰
.signWith(SignatureAlgorithm.HS512, "helloworld")
.compact();
這里貼出小編文末案例demo源碼中關(guān)于登錄認(rèn)證處理中的使用
@Component
public class AdminAuthenticationProvider implements AuthenticationProvider {
@Autowired
UserDetailsServiceImpl userDetailsService;
@Autowired
private UserMapper userMapper;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 獲取前端表單中輸入后返回的用戶(hù)名、密碼
String userName = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
SecurityUser userInfo = (SecurityUser) userDetailsService.loadUserByUsername(userName);
boolean isValid = PasswordUtils.isValidPassword(password, userInfo.getPassword(), userInfo.getCurrentUserInfo().getSalt());
// 驗(yàn)證密碼
if (!isValid) {
throw new BadCredentialsException("密碼錯(cuò)誤!");
}
// 前后端分離情況下 處理邏輯...
// 更新登錄令牌
// 當(dāng)前用戶(hù)所擁有角色代碼
String roleCodes = userInfo.getRoleCodes();
// 生成jwt訪(fǎng)問(wèn)令牌
String jwt = Jwts.builder()
// 用戶(hù)角色
.claim(Constants.ROLE_LOGIN, roleCodes)
// 主題 - 存用戶(hù)名
.setSubject(authentication.getName())
// 過(guò)期時(shí)間 - 30分鐘
.setExpiration(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
// 加密算法和密鑰
.signWith(SignatureAlgorithm.HS512, Constants.SALT)
.compact();
User user = userMapper.selectById(userInfo.getCurrentUserInfo().getId());
user.setToken(jwt);
userMapper.updateById(user);
userInfo.getCurrentUserInfo().setToken(jwt);
return new UsernamePasswordAuthenticationToken(userInfo, password, userInfo.getAuthorities());
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
前端頁(yè)面保存的jwt令牌格式如下:
我們?cè)谠L(fǎng)問(wèn)每一個(gè)url請(qǐng)求的時(shí)候,在統(tǒng)一認(rèn)證的地方獲取jwt中我們需要的信息然后認(rèn)證即可,【注: Claims
中存放著我們需要的信息】
例如: 我們可以將用戶(hù)名、密碼存放jwt中,然后在認(rèn)證的時(shí)候讀取到其中的用戶(hù)信息,然后查詢(xún)數(shù)據(jù)庫(kù)認(rèn)證用戶(hù),如果滿(mǎn)足條件即成功訪(fǎng)問(wèn),如果不滿(mǎn)足條件即拋出異常處理
溫馨小提示:如果jwt令牌過(guò)期,會(huì)拋出
ExpiredJwtException
異常,我們需要攔截到,然后交給認(rèn)證失敗處理器中處理,然后返回給前端,這里根據(jù)個(gè)人業(yè)務(wù)實(shí)際處理即可~
// 獲取jwt中的信息
Claims claims = Jwts.parser().setSigningKey("helloworld").parseClaimsJws(jwtToken.replace("Bearer", "")).getBody();
// 獲取當(dāng)前登錄用戶(hù)名
System.out.println("獲取當(dāng)前登錄用戶(hù)名: " + claims.getSubject());
小編項(xiàng)目中認(rèn)證過(guò)濾器中的使用如下:
@Slf4j
@Component
public class MyAuthenticationFilter extends OncePerRequestFilter {
@Autowired
AdminAuthenticationEntryPoint authenticationEntryPoint;
private final UserDetailsServiceImpl userDetailsService;
protected MyAuthenticationFilter(UserDetailsServiceImpl userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request);
MultiReadHttpServletResponse wrappedResponse = new MultiReadHttpServletResponse(response);
StopWatch stopWatch = new StopWatch();
try {
stopWatch.start();
// 前后端分離情況下,前端登錄后將token儲(chǔ)存在cookie中,每次訪(fǎng)問(wèn)接口時(shí)通過(guò)token去拿用戶(hù)權(quán)限
String jwtToken = wrappedRequest.getHeader(Constants.REQUEST_HEADER);
log.debug("后臺(tái)檢查令牌:{}", jwtToken);
if (StringUtils.isNotBlank(jwtToken)) {
// JWT相關(guān)start ===========================================
// 獲取jwt中的信息
Claims claims = Jwts.parser().setSigningKey(Constants.SALT).parseClaimsJws(jwtToken.replace("Bearer", "")).getBody();
// 獲取當(dāng)前登錄用戶(hù)名
System.out.println("獲取當(dāng)前登錄用戶(hù)名: " + claims.getSubject());
// TODO 如需使用jwt特性在此做處理~
// JWT相關(guān)end ===========================================
// 檢查token
SecurityUser securityUser = userDetailsService.getUserByToken(jwtToken);
if (securityUser == null || securityUser.getCurrentUserInfo() == null) {
throw new BadCredentialsException("TOKEN已過(guò)期,請(qǐng)重新登錄!");
}
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities());
// 全局注入角色權(quán)限信息和登錄用戶(hù)基本信息
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(wrappedRequest, wrappedResponse);
} catch (ExpiredJwtException e) {
// jwt令牌過(guò)期
SecurityContextHolder.clearContext();
this.authenticationEntryPoint.commence(wrappedRequest, response, null);
} catch (AuthenticationException e) {
SecurityContextHolder.clearContext();
this.authenticationEntryPoint.commence(wrappedRequest, response, e);
} finally {
stopWatch.stop();
}
}
}
簡(jiǎn)單的入門(mén)使用就是這樣了
jwt依賴(lài)
生成jwt令牌
返回給前端保存到瀏覽器請(qǐng)求頭
中用戶(hù)信息
然后做認(rèn)證處理
,如果滿(mǎn)足條件成功訪(fǎng)問(wèn),如果不滿(mǎn)足交給認(rèn)證失敗處理器返回指定內(nèi)容給前端https://gitee.com/zhengqingya/java-workspace
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。