本篇文章給大家分享的是有關(guān)如何基于springSecurity的Json Web Token的實(shí)現(xiàn),小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
目前創(chuàng)新互聯(lián)公司已為數(shù)千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、網(wǎng)站托管、服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計(jì)、尼河口網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
GitHub地址
Spring Security
,一種基于 Spring AOP
和 Servlet
過濾器的安全框架。它提供全面的安全性解決方案,同時(shí)在 Web
請(qǐng)求級(jí)和方法調(diào)用級(jí)處理身份確認(rèn)和授權(quán)。。
來自Spring
全家桶系列,與SpringBoot
無縫銜接。為應(yīng)用系統(tǒng)提供聲明式的安全訪問控制功能,減少了為企業(yè)系統(tǒng)安全控制編寫大量重復(fù)代碼的工作。
JSON Web Token(JWT)
準(zhǔn)確來說是一個(gè)規(guī)范。實(shí)際上就是一個(gè)字符串,它由三部分組成——頭部(Header
)、載荷(playload
)與簽名(signature
)。
頭部(Header
)用于描述關(guān)于該JWT
的最基本的信息,即該JWT
本身的信息聲明,如簽名所用算法。
載荷(playload
)是存放有效信息的地方。其中信息又分為三個(gè)部分——聲明部分、公共部分(subject
)、私有部分(claim
)。
簽證(signature
)需要base64
加密后的header
和base64
加密后的payload
使用.連接組成的字符串,然后通過header
中聲明的加密方式進(jìn)行加鹽secret
組合加密構(gòu)成(注意:secret
是保存在服務(wù)器端的)。
在分布式中直接根據(jù)token
取出保存的用戶信息,以及對(duì)token
可用性校驗(yàn),單點(diǎn)登錄更為簡(jiǎn)單。
Java
版本:1.8
構(gòu)建工具:Gradle
(目前國內(nèi)主流構(gòu)建工具依然是Maven
,但是筆者用過Gradle
之后就不想再用Maven
了,因?yàn)?code>Gradle是真的方便很多。其倉庫結(jié)構(gòu)向下兼容Maven
,也就是說可以使用任何Maven
倉庫。
build.gradle
文件:
plugins { id 'org.springframework.boot' version '2.2.0.RELEASE' id 'io.spring.dependency-management' version '1.0.8.RELEASE' id 'java' } group = 'org.zuoyu' version = '1.0.0' sourceCompatibility = '1.8' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { // 這里使用的是阿里巴巴的Maven倉庫 maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' runtimeOnly 'MySQL:mysql-connector-java' annotationProcessor 'org.projectlombok:lombok' // jwt依賴 runtime('io.jsonwebtoken:jjwt-jackson:0.10.7') runtime('io.jsonwebtoken:jjwt-impl:0.10.7') compile('io.jsonwebtoken:jjwt-api:0.10.7') testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } testImplementation 'org.springframework.security:spring-security-test' } test { useJUnitPlatform() }
JwtConstants.java
是我自定義的final
變量類)security
的配置文件中,將session
管理器關(guān)閉,沒有必要使用session
。JwtTokenUtils.java
(JWT的工具類)/** * 構(gòu)建JWT * * @param subject - 實(shí)體 * @param authorities - 權(quán)限 * @param expiration - 保留時(shí)間 * @return - token */ private static String createJwt(String subject, String authorities, long expiration) { long nowMillis = System.currentTimeMillis(); return Jwts.builder() .setId(JwtConstants.createTokenId()) .signWith(SECRET_KEY, SignatureAlgorithm.HS256) .setIssuer(JwtConstants.JWT_ISSUER) .setSubject(subject) .claim(JwtConstants.ROLE_CLAIMS, authorities) .setIssuedAt(new Date(nowMillis)) .setNotBefore(new Date(nowMillis)) .setExpiration(new Date(nowMillis + expiration * 1000L)) .compact(); }
在這里我們使用官方依賴包中的Jwts.builder()
方法,創(chuàng)建一個(gè)token
,其中——
signWith
就是設(shè)置私密鑰與加密方式,SECRET_KEY
為私密鑰,SignatureAlgorithm.HS256
為加密方式。
setSubject
為設(shè)置公共部分,該部分在客戶端可解密。
claim
為設(shè)置私有部分,其參數(shù)為key
—value
形式。
setIssuedAt
為token
的簽發(fā)時(shí)間。
setNotBefore
為token
的生效時(shí)間。
setExpiration
為token
的失效時(shí)間。
解析token
:
/** * 解析token * * @param token - * @return - Claims */ private static Claims parseJwt(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); }
在這里重點(diǎn)在與setSigningKey
,傳入我們?cè)趧?chuàng)建時(shí)候的私密鑰SECRET_KEY
。
還有幾個(gè)與security
方便交互的方法:
/** * 根據(jù)賬戶構(gòu)建token * * @param user - 賬戶 * @return - */ public static String createToken(User user, boolean isRememberMe) { long expiration = isRememberMe ? JwtConstants.EXPIRATION_REMEMBER : JwtConstants.EXPIRATION; String spacer = ","; List<string> authorities = Arrays.stream(user.getRoles().split(spacer)) .map(role -> "ROLE_" + role) .collect(Collectors.toList()); return createJwt(JsonUtil.beanToJsonString(user), JsonUtil.objectToJsonString(authorities), expiration); } /** * 獲取用戶 * * @param token - token * @return - User */ public static User getUserByToken(String token) { String subject = parseJwt(token).getSubject(); return JsonUtil.jsonStringToBean(subject, User.class); } /** * 獲取用戶的權(quán)限 * @param token - token * @return - 權(quán)限列表 */ public static Collection<!--? extends GrantedAuthority--> getAuthoritiesByToken(String token) { String roles = parseJwt(token).get(JwtConstants.ROLE_CLAIMS).toString(); return JsonUtil.jsonStringToCollection(roles, SimpleGrantedAuthority.class); }
AuthenticationSuccessHandlerImpl.java
(Security登錄成功后的執(zhí)行行為)/** * 登錄成功的實(shí)現(xiàn). * * @author zuoyu **/ @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { String rememberMe = request.getParameter(JwtConstants.USER_LOGIN_REMEMBER_ME); boolean isRememberMe = Boolean.parseBoolean(rememberMe); User principal = (User) authentication.getPrincipal(); String token = JwtTokenUtils.createToken(principal, isRememberMe); response.setContentType("application/json;charset=utf-8"); response.setHeader(JwtConstants.TOKEN_HEADER, token); response.setStatus(HttpServletResponse.SC_OK); PrintWriter responseWriter = response.getWriter(); responseWriter.write("{\"message\":\"登錄成功\"}"); responseWriter.flush(); responseWriter.close(); } }
這段代碼主要思路是——登錄成功后,在authentication
中獲取已經(jīng)認(rèn)證成功的用戶信息(user
),然后將該user
轉(zhuǎn)換為token
并返回給客戶端。其中的isRememberMe
是根據(jù)是否為true
給予token
不同的有效時(shí)間(查看完整源代碼)。
JwtAuthorizationFilter.java
(自定義基于JWT認(rèn)證的過濾器)/** * JWT的權(quán)限過濾器. * * @author zuoyu * @program jwt * @create 2019-10-17 16:26 **/ @Slf4j public class JwtAuthorizationFilter extends BasicAuthenticationFilter { public JwtAuthorizationFilter(AuthenticationManager authenticationManager) { super(authenticationManager); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String token = request.getHeader(JwtConstants.TOKEN_HEADER); if (StringUtils.isEmpty(token)) { chain.doFilter(request, response); return; } User user = JwtTokenUtils.getUserByToken(token); Collection<!--? extends GrantedAuthority--> authorities = JwtTokenUtils.getAuthoritiesByToken(token); UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken( user, null, authorities); SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); super.doFilterInternal(request, response, chain); } }
這段代碼的從請(qǐng)求中獲取token
,并將從token
中解析出用戶信息(user
)和權(quán)限信息(authorities
)。并根據(jù)用戶信息(user
)和權(quán)限信息(authorities
)創(chuàng)建屬于security
框架的權(quán)限身份(authentication
),將其存入當(dāng)前的security
環(huán)境。
userName
passWord
rememberMe
登錄之后,在響應(yīng)Response
的頭Headers
里有字段Authorization
,該值就是Token
。
后續(xù)的訪問需在Request
的頭Headers
內(nèi)攜帶字段Authorization
和其值,以此來表示身份。
rememberMe
默認(rèn)時(shí)效為一小時(shí),為true
時(shí)時(shí)效7天,設(shè)置路徑在org.zuoyu.security.jwt.constants.JwtConstants.java
。
測(cè)試路徑查看org.zuoyu.security.jwt.controller.AuthController.java
類。
以上就是如何基于springSecurity的Json Web Token的實(shí)現(xiàn),小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
本文名稱:如何基于springSecurity的JsonWebToken的實(shí)現(xiàn)
網(wǎng)頁網(wǎng)址:http://www.rwnh.cn/article16/ghcggg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、網(wǎng)站收錄、搜索引擎優(yōu)化、網(wǎng)站設(shè)計(jì)公司、小程序開發(fā)、企業(yè)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)