SpringBoot+SpringSecurity+JWT實RESTfulAPI許可權控制
工具類JwtTokenUtil:
dao介面:package org.security.util; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.security.entity.SysUser; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import java.io.Serializable; import java.util.Date; import java.util.HashMap; import java.util.Map; @Component public class JwtTokenUtil implements Serializable { private static final long serialVersionUID = -3301605591108950415L; private static final String CLAIM_KEY_USERNAME = "sub"; private static final String CLAIM_KEY_CREATED = "created"; @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; public String getUsernameFromToken(String token) { String username; try { final Claims claims = getClaimsFromToken(token); username = claims.getSubject(); } catch (Exception e) { username = null; } return username; } public Date getCreatedDateFromToken(String token) { Date created; try { final Claims claims = getClaimsFromToken(token); created = new Date((Long) claims.get(CLAIM_KEY_CREATED)); } catch (Exception e) { created = null; } return created; } public Date getExpirationDateFromToken(String token) { Date expiration; try { final Claims claims = getClaimsFromToken(token); expiration = claims.getExpiration(); } catch (Exception e) { expiration = null; } return expiration; } private Claims getClaimsFromToken(String token) { Claims claims; try { claims = Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody(); } catch (Exception e) { claims = null; } return claims; } private Date generateExpirationDate() { return new Date(System.currentTimeMillis() + expiration * 1000); } private Boolean isTokenExpired(String token) { final Date expiration = getExpirationDateFromToken(token); return expiration.before(new Date()); } private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) { return (lastPasswordReset != null && created.before(lastPasswordReset)); } public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(); claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername()); claims.put(CLAIM_KEY_CREATED, new Date()); return generateToken(claims); } String generateToken(Map<String, Object> claims) { return Jwts.builder() .setClaims(claims) .setExpiration(generateExpirationDate()) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) { final Date created = getCreatedDateFromToken(token); return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset) && !isTokenExpired(token); } public String refreshToken(String token) { String refreshedToken; try { final Claims claims = getClaimsFromToken(token); claims.put(CLAIM_KEY_CREATED, new Date()); refreshedToken = generateToken(claims); } catch (Exception e) { refreshedToken = null; } return refreshedToken; } public Boolean validateToken(String token, UserDetails userDetails) { SysUser user = (SysUser) userDetails; final String username = getUsernameFromToken(token); final Date created = getCreatedDateFromToken(token); // final Date expiration = getExpirationDateFromToken(token); return ( username.equals(user.getUsername()) && !isTokenExpired(token) && !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate())); } }
package org.security.dao;
import org.security.entity.SysUser;
public interface AuthService {
SysUser register(SysUser userToAdd);
String login(String username, String password);
String refresh(String oldToken);
}
dao介面實現類(service業務類):controller控制類:package org.security.service; import org.security.dao.AuthService; import org.security.dao.SysUserRepository; import org.security.entity.SysUser; import org.security.util.JwtTokenUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import java.util.Date; import static java.util.Arrays.asList; @Service public class AuthServiceImpl implements AuthService { private AuthenticationManager authenticationManager; private UserDetailsService userDetailsService; private JwtTokenUtil jwtTokenUtil; private SysUserRepository userRepository; @Value("${jwt.tokenHead}") private String tokenHead; @Autowired public AuthServiceImpl( AuthenticationManager authenticationManager, UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, SysUserRepository userRepository) { this.authenticationManager = authenticationManager; this.userDetailsService = userDetailsService; this.jwtTokenUtil = jwtTokenUtil; this.userRepository = userRepository; } @Override public SysUser register(SysUser userToAdd) { final String username = userToAdd.getUsername(); if(userRepository.findByUsername(username)!=null) { return null; } BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); final String rawPassword = userToAdd.getPassword(); userToAdd.setPassword(encoder.encode(rawPassword)); userToAdd.setLastPasswordResetDate(new Date()); // userToAdd.setRoles(asList("ROLE_USER")); return userRepository.save(userToAdd); } @Override public String login(String username, String password) { UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password); // Perform the security final Authentication authentication = authenticationManager.authenticate(upToken); SecurityContextHolder.getContext().setAuthentication(authentication); // Reload password post-security so we can generate token final UserDetails userDetails = userDetailsService.loadUserByUsername(username); final String token = jwtTokenUtil.generateToken(userDetails); return token; } @Override public String refresh(String oldToken) { final String token = oldToken.substring(tokenHead.length()); String username = jwtTokenUtil.getUsernameFromToken(token); SysUser user = (SysUser) userDetailsService.loadUserByUsername(username); if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())){ return jwtTokenUtil.refreshToken(token); } return null; } }
package org.security.controller; import org.security.dao.AuthService; import org.security.entity.SysUser; import org.security.service.JwtAuthenticationRequest; import org.security.service.JwtAuthenticationResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; import org.springframework.security.core.AuthenticationException; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; @RestController public class AuthController { @Value("${jwt.header}") private String tokenHeader; @Autowired private AuthService authService; @RequestMapping(value = "/auth/login", method = RequestMethod.POST) public ResponseEntity<?> createAuthenticationToken( String username,String password ) throws AuthenticationException{ // @RequestBody JwtAuthenticationRequest authenticationRequest final String token = authService.login(username,password); // Return the token return ResponseEntity.ok(new JwtAuthenticationResponse(token)); } @RequestMapping(value = "/auth/refresh", method = RequestMethod.GET) public ResponseEntity<?> refreshAndGetAuthenticationToken( HttpServletRequest request) throws AuthenticationException{ String token = request.getHeader(tokenHeader); String refreshedToken = authService.refresh(token); if(refreshedToken == null) { return ResponseEntity.badRequest().body(null); } else { return ResponseEntity.ok(new JwtAuthenticationResponse(refreshedToken)); } } @RequestMapping(value = "${jwt.route.authentication.register}", method = RequestMethod.POST) public SysUser register(@RequestBody SysUser addedUser) throws AuthenticationException{ return authService.register(addedUser); } }
接在來就是最重要的filter類:
package org.security.config;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.security.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Value("${jwt.header}")
private String tokenHeader;
@Value("${jwt.tokenHead}")
private String tokenHead;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String authHeader = request.getHeader(this.tokenHeader);
if (authHeader != null && authHeader.startsWith(tokenHead)) {
final String authToken = authHeader.substring(tokenHead.length()); // The part after "Bearer "
String username = jwtTokenUtil.getUsernameFromToken(authToken);
logger.info("checking authentication " + username);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(
request));
logger.info("authenticated user " + username + ", setting security context");
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
chain.doFilter(request, response);
}
}
將security中配置檔案註解去掉,去掉之後如下所示:package org.security.config;
import org.security.service.CustomUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
protected UserDetailsService customUserService() {
return new CustomUserService();
}
@Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
// 設定UserDetailsService
.userDetailsService(customUserService())
// 使用BCrypt進行密碼的hash
.passwordEncoder(passwordEncoder());
}
// 裝載BCrypt密碼編碼器
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
return new JwtAuthenticationTokenFilter();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserService());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// 由於使用的是JWT,我們這裡不需要csrf
.csrf().disable()
// 基於token,所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// 允許對於網站靜態資源的無授權訪問
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js"
).permitAll()
// 對於獲取token的rest api要允許匿名訪問
.antMatchers("/auth/**").permitAll()
.antMatchers("/admin/**").hasIpAddress("127.0.0.1")
.antMatchers("/admin/**").access("hasAuthority('ROLE_ADMIN')")
// .anyRequest().authenticated().and().formLogin().loginPage("/login")
// .failureUrl("/login?error").permitAll().and().logout().permitAll();
// 除上面外的所有請求全部需要鑑權認證
.anyRequest().authenticated();
// 新增JWT filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
// 禁用快取
httpSecurity.headers().cacheControl();
}
}
到這邊jwt整合也介紹了,現在我們就可以postman來進行測試。測試結果如下所示:
生成token:
重新整理token:
不帶token訪問介面:
帶token但是許可權不夠:
帶token而且許可權也夠:
到這裡關於 SpringBoot+SpringSecurity+JWT就基本結束了,這篇部落格我重點是將如何通過程式碼來實現這個功能,關於程式碼本身沒有很細緻的介紹。關於程式碼功能的介紹,例如怎麼通過註解配置許可權控制,如何通過配置來進行許可權控制,token更新和驗證等等的細節,我會在我這篇部落格的教學視訊中介紹,視訊地址:點選開啟連結
GitHub地址:點選開啟連結
如果大家對文章有什麼問題或者疑意之類的,可以加我訂閱號在上面留言,訂閱號上面我會定期更新最新部落格。如果嫌麻煩可以直接加我wechat:lzqcode相關推薦
SpringBoot+SpringSecurity+JWT實RESTfulAPI許可權控制
工具類JwtTokenUtil:package org.security.util; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import or
SpringBoot--- SpringSecurity進行登出,許可權控制
## SpringBoot--- SpringSecurity進行登出,許可權控制 ### 環境 IDEA :2020.1 Maven:3.5.6 SpringBoot: **2.0.9** (與此前整合的版本2.3.3 不同,版本適配問題,為配合使用降級) ### 1、登出 這裡也有一個前提問題
springboot+shiro+mybatis實現角色許可權控制
背景 spring+spirngmvc+shiro的整合已經有很多了,之前的專案中也用過,但是最近想在springboot中使用shiro這樣,其他專案需要的時候只需要把它依賴進來就可以直接使用,至於shiro的原理其他的blog都有很多介紹。這裡只講幾個重點
Springboot+SpringMVC+Myabtis整合shiro許可權控制
最近也被這個難題搞的我頭都大了額。寫下此篇文章獻給自己和廣大朋友。如果有不懂的地方可以加企鵝號詢問哦。 企鵝號:2054861587,不一定會時時在,但如果有空的話就會給你回答 maven依賴: <dependency> <groupId>
SpringBoot 結合SpringSecurity+Jwt實現許可權認證
首先建立RBAC 許可權系統表 /* MySQL Backup Database: test Backup Time: 2018-09-12 11:53:20 */ SET FOREIGN_KEY_CHECKS=0; DROP TABLE IF EXISTS `test`
springboot+springsecurity+cas實現sso,並開啟註解方法級別的許可權控制
springsecurity整合cas springsecurity的springsecurityfilterchian中有一個cas的攔截器位置,因此可以通過它把cas整合進springsecurity中 cas負責認證,security通過userDetails負責載入許可權,通過認證管理器
SpringBoot整合Springsecurity實現資料庫登入以及許可權控制
我們今天使用SpringBoot來整合SpringSecurity,來吧,不多BB 首先呢,是一個SpringBoot 專案,連線資料庫,這裡我使用的是mybaties.mysql, 下面是資料庫的表 DROP TABLE IF EXISTS `xy_role`; CR
成長記錄貼之springboot+shiro(二) {完成一個完整的許可權控制,詳細步驟}
近一個月比較忙,公司接了一個新專案,領導要求用shiro進行安全管理,而且全公司只有我一個java,從專案搭建到具體介面全是一個人再弄。不過剛好前段時間大概學習了一下shiro的使用,還算順利。 &n
springboot使用Spring Security+OAuth2做許可權控制
文章來源:http://lxgandlz.cn/404.html 前面有一篇文章Spring+Spring Security+OAuth2實現REST API許可權控制,講了Spring+Spring Security+OAuth2來實現REST API許可權
springboot配置shiro許可權管理,網搜搜採集網站許可權控制程式碼
import outshine.shiro.authc.AccountSubjectFactory; import outshine.shiro.filter.AuthenticatedFilter; import outshine.shiro.realm.AccountRealm; import or
SpringBoot2.0整合SpringSecurity並實現驗證碼和許可權控制
使用SpringBoot2.0 整合SpringSecurity加入kaptcha驗證碼,使用redis實現session共享,請看原始碼,附上資料庫指令碼,絕對可以跑起來,原始碼地址為 1、pom檔案 <?xml version="1.0" encoding=
Springboot: Springboot + spring boot admin 監控 spring security許可權控制
Springboot admin 很好的提供了對Springboot的監控,但是不建議直接將admin整合到已有的專案中。於是我另起一個專案,考慮到不能讓所有人都能看到這些資料了,於是引入了spring security。 本次使用的是spring-boot-admin-s
SpringBoot+shiro整合學習之登入認證和許可權控制
學習任務目標 使用者必須要登陸之後才能訪問定義連結,否則跳轉到登入頁面。 對連結進行許可權控制,只有噹噹前登入使用者有這個連結訪問許可權才可以訪問,否則跳轉到指定頁面。 輸入錯誤密碼使用者名稱或則使用者被設定為靜止登入,返回相應json串資訊 匯
springboot整合security實現基於url的許可權控制
許可權控制基本上是任何一個web專案都要有的,為此spring為我們提供security模組來實現許可權控制,網上找了很多資料,但是提供的demo程式碼都不能完全滿足我的需求,因此自己整理了一版。 在上程式碼之前,大家需要理解兩個過程:認證和授權 使用者登陸,會被AuthenticationPro
springboot整合shiro 實現許可權控制
shiro apache shiro 是一個輕量級的身份驗證與授權框架,與spring security 相比較,簡單易用,靈活性高,springboot本身是提供了對security的支援,畢竟是自家的東西。springboot暫時沒有整合shiro,這得自
SpringBoot + SpringSecurity 控制授權
授權簡介 一般的人會認為,不同的角色登入進同一個系統,根據角色許可權的不同,看到的選單不同就是控制授權。其實並不是的,選單的是否顯示只是前端互動上的一個設計而已,真正需要授權的地方的介面的訪問。 普通的系統通常會有兩個端,一個是給使用者用的業務系統(比如購
SpringBoot學習筆記(六):SpringBoot實現Shiro登入控制和許可權控制
登入模組:在登入時必須呼叫 授權模組:不是一登入就調動,而是當角色許可權控制時才會呼叫 登入控制 環境搭建在上一篇。 資料庫表 表名:role 欄位:id rolename 表名:user 欄位:id username sex roleid 在程式碼中簡歷資料庫表對應的實
前後端分離 SpringBoot + SpringSecurity 許可權解決方案
一、前言 而公司這邊都是前後端分離鮮明的,前端不要接觸過多的業務邏輯,都由後端解決,基本思路是這樣的: 服務端通過 JSON字串,告訴前端使用者有沒有登入、認證,前端根據這些提示跳轉對應的登入頁、認證頁等。 二、程式碼 下面給個示例,該自上述的之
SpringBoot中使用Spring Security實現許可權控制
Spring Security,這是一個專門針對基於Spring的專案的安全框架,它主要是利用了AOP來實現的。以前在Spring框架中使用Spring Security需要我們進行大量的XML配置,但是,Spring Boot針對Spring Security
springBoot+springSecurity 資料庫動態管理使用者、角色、許可權(二)
序: 本文使用springboot+mybatis+SpringSecurity 實現資料庫動態的管理使用者、角色、許可權管理 本文細分角色和許可權,並將使用者、角色、許可權和資源均採用資料庫儲存,並且自定義濾器,代替原有的FilterSecurityInt