您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關如何基于springSecurity的Json Web Token的實現,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
GitHub地址
Spring Security
,一種基于 Spring AOP
和 Servlet
過濾器的安全框架。它提供全面的安全性解決方案,同時在 Web
請求級和方法調用級處理身份確認和授權。。
來自Spring
全家桶系列,與SpringBoot
無縫銜接。為應用系統提供聲明式的安全訪問控制功能,減少了為企業系統安全控制編寫大量重復代碼的工作。
JSON Web Token(JWT)
準確來說是一個規范。實際上就是一個字符串,它由三部分組成——頭部(Header
)、載荷(playload
)與簽名(signature
)。
頭部(Header
)用于描述關于該JWT
的最基本的信息,即該JWT
本身的信息聲明,如簽名所用算法。
載荷(playload
)是存放有效信息的地方。其中信息又分為三個部分——聲明部分、公共部分(subject
)、私有部分(claim
)。
簽證(signature
)需要base64
加密后的header
和base64
加密后的payload
使用.連接組成的字符串,然后通過header
中聲明的加密方式進行加鹽secret
組合加密構成(注意:secret
是保存在服務器端的)。
在分布式中直接根據token
取出保存的用戶信息,以及對token
可用性校驗,單點登錄更為簡單。
Java
版本:1.8
構建工具:Gradle
(目前國內主流構建工具依然是Maven
,但是筆者用過Gradle
之后就不想再用Maven
了,因為Gradle
是真的方便很多。其倉庫結構向下兼容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
管理器關閉,沒有必要使用session
。JwtTokenUtils.java
(JWT的工具類)/** * 構建JWT * * @param subject - 實體 * @param authorities - 權限 * @param expiration - 保留時間 * @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()
方法,創建一個token
,其中——
signWith
就是設置私密鑰與加密方式,SECRET_KEY
為私密鑰,SignatureAlgorithm.HS256
為加密方式。
setSubject
為設置公共部分,該部分在客戶端可解密。
claim
為設置私有部分,其參數為key
—value
形式。
setIssuedAt
為token
的簽發時間。
setNotBefore
為token
的生效時間。
setExpiration
為token
的失效時間。
解析token
:
/** * 解析token * * @param token - * @return - Claims */ private static Claims parseJwt(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); }
在這里重點在與setSigningKey
,傳入我們在創建時候的私密鑰SECRET_KEY
。
還有幾個與security
方便交互的方法:
/** * 根據賬戶構建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); } /** * 獲取用戶的權限 * @param token - token * @return - 權限列表 */ 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登錄成功后的執行行為)/** * 登錄成功的實現. * * @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
中獲取已經認證成功的用戶信息(user
),然后將該user
轉換為token
并返回給客戶端。其中的isRememberMe
是根據是否為true
給予token
不同的有效時間(查看完整源代碼)。
JwtAuthorizationFilter.java
(自定義基于JWT認證的過濾器)/** * JWT的權限過濾器. * * @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); } }
這段代碼的從請求中獲取token
,并將從token
中解析出用戶信息(user
)和權限信息(authorities
)。并根據用戶信息(user
)和權限信息(authorities
)創建屬于security
框架的權限身份(authentication
),將其存入當前的security
環境。
userName
passWord
rememberMe
登錄之后,在響應Response
的頭Headers
里有字段Authorization
,該值就是Token
。
后續的訪問需在Request
的頭Headers
內攜帶字段Authorization
和其值,以此來表示身份。
rememberMe
默認時效為一小時,為true
時時效7天,設置路徑在org.zuoyu.security.jwt.constants.JwtConstants.java
。
測試路徑查看org.zuoyu.security.jwt.controller.AuthController.java
類。
以上就是如何基于springSecurity的Json Web Token的實現,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。