vue2+springsecurity權(quán)限系統(tǒng)的實(shí)現(xiàn)
準(zhǔn)備內(nèi)容
新建項(xiàng)目,SpringBoot采用2.7.11,spring-boot-starter-security,vue 2.0
默認(rèn)會自動啟動攔截裝置,可以這樣取消,先這樣配置一下
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})JWT 校驗(yàn)用戶的憑證(頭部,載荷,簽證)
引入依賴
<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>邏輯:用戶登錄后,請求頭中加一個token參數(shù),如果有則表示可以訪問,沒有就不能訪問,這是一個小測試還是有點(diǎn)缺陷的
SpringSecurity 權(quán)限控制
一共有兩個最主要攔截器
登陸驗(yàn)證攔截器AuthenticationProcessingFilter
資源管理攔截器AbstractSecurityInterceptor
但攔截器里面的實(shí)現(xiàn)需要一些組件來實(shí)現(xiàn)分別是
AuthenticationManager認(rèn)證管理器
accessDecisionManager決策管理器等組件來支撐。
流程圖解讀:
用戶提交用戶名、密碼被SecurityFilterChain中的 UsernamePasswordAuthenticationFilter 過濾器獲取到,封裝為請求Authentication,通常情況下是UsernamePasswordAuthenticationToken這個實(shí) 現(xiàn)類。
然后過濾器將Authentication提交至認(rèn)證管理器(AuthenticationManager)進(jìn)行認(rèn)證 。
認(rèn)證成功后, AuthenticationManager 身份管理器返回一個被填充滿了信息的(包括上面提到的權(quán) 限信息, 身份信息,細(xì)節(jié)信息,但密碼通常會被移除) Authentication 實(shí)例。
SecurityContextHolder 安全上下文容器將第3步填充了信息的 Authentication
通過 SecurityContextHolder.getContext().setAuthentication(…)方法,設(shè)置到其中。 可以看出 AuthenticationManager接口(認(rèn)證管理器)是認(rèn)證相關(guān)的核心接口,也是發(fā)起認(rèn)證的出發(fā)點(diǎn),它的實(shí) 現(xiàn)類為ProviderManager。而Spring Security支持多種認(rèn)證方式,因此ProviderManager維護(hù)著一個 List 列表,存放多種認(rèn)證方式,最終實(shí)際的認(rèn)證工作是由 AuthenticationProvider完成的。咱們知道 web表單的對應(yīng)的AuthenticationProvider實(shí)現(xiàn)類為 DaoAuthenticationProvider,它的內(nèi)部又維護(hù)著 一個UserDetailsService負(fù)責(zé)UserDetails的獲取。最終 AuthenticationProvider將UserDetails填充至 Authentication。
現(xiàn)在關(guān)掉之前的SecurityAutoConfiguration.class,打開是不是直接跳轉(zhuǎn)到了登錄頁面呢,無法訪問接口了
配置 SpringSecurity
先說下創(chuàng)建token的工具類
/**
* 簽發(fā)JWT
*
* @param id 用戶ID
* @param subject 可以是JSON數(shù)據(jù) 盡可能少
* @param ttlMillis 不知道
* @return 結(jié)果
*/
public static String createJWT(String id, String subject, long ttlMillis) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
// 獲取當(dāng)前時間毫秒
long nowMillis = System.currentTimeMillis();
// 獲取當(dāng)前時間日期類型
Date now = new Date(nowMillis);
// 生成一個加密的key
SecretKey secretKey = generalKey();
JwtBuilder builder = Jwts.builder()
.setId(id)
.setSubject(subject) // 主題
.setIssuer("ChiHaiKeJi2016") // 簽發(fā)者
.setIssuedAt(now) // 簽發(fā)時間
.signWith(signatureAlgorithm, secretKey); // 簽名算法以及密匙
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date expDate = new Date(expMillis);
builder.setExpiration(expDate); // 過期時間
}
return builder.compact();
}
/**
* 生成jwt token
* @param username 用戶名
*/
public static String genJwtToken(String username) {
return createJWT(username, username, 60 * 60 * 1000);
}
/**
* 生成加密Key
*/
public static SecretKey generalKey() {
// 目前只知道這個方法生成一個key,并用base64解碼
byte[] encodedKey = Base64.decode(JwtConstant.JWT_SECERT);
// 目前不知道啥意思
return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
}配置信息--新建SecurityConfig
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
// 白名單
private static final String[] URL_WHITE_LIST = {"/login"};
@Resource
private LoginHandler loginHandler;
// 密碼加密方式
@Bean
protected PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
// 開啟跨域 以及csrf攻擊關(guān)閉
httpSecurity.cors().and().csrf().disable()
// 登錄登出配置
.formLogin()
// 登錄成功接口
.successHandler(loginHandler)
// 登錄失敗的接口
.failureHandler(loginHandler)
// .and().logout().logoutSuccessHandler()
// session禁用配置
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 無狀態(tài),前后端分離
// 攔截規(guī)則配置 // // 白名單內(nèi)容放行
.and().authorizeRequests().antMatchers(URL_WHITE_LIST).permitAll()
// 需要認(rèn)證
.anyRequest().authenticated();
return httpSecurity.build();
}
}配置登錄失敗與成功接口---新建---LoginHandler 處理類
/**
* 登錄成功與失敗處理器
*/
@Component
public class LoginHandler implements AuthenticationSuccessHandler, AuthenticationFailureHandler {
// 登錄成功的
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
ServletOutputStream stream = response.getOutputStream();
// 獲取token
String token = JwtUtils.genJwtToken("user");
// 寫入數(shù)據(jù)
stream.write(JSONUtil.toJsonStr(new Result("登錄成功", token)).getBytes());
stream.flush();
stream.close();
}
// 登錄失敗的
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
ServletOutputStream stream = response.getOutputStream();
String message = exception.getMessage();
if (exception instanceof BadCredentialsException) {
message = "用戶名或者密碼錯誤!";
}
stream.write(JSONUtil.toJsonStr(new Result(message)).getBytes(StandardCharsets.UTF_8));
stream.flush();
stream.close();
}
}在用戶service實(shí)現(xiàn)類中自定義查詢數(shù)據(jù)庫
@Service
public class SysUserServiceImpl implements SysUserService, UserDetailsService {
@Resource
private SysUserMapper sysUserMapper;
// 自定義查詢參數(shù)是用戶名
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LambdaQueryWrapper<SysUser> sysUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
sysUserLambdaQueryWrapper.eq(SysUser::getUsername, username);
SysUser user = sysUserMapper.selectOne(sysUserLambdaQueryWrapper);
if (user == null) {
throw new UsernameNotFoundException("用戶名或密碼錯誤!");
} else if ("1".equals(user.getStatus())) {
throw new UsernameNotFoundException("該用戶已被封禁!");
}
// 第三個是擁有權(quán)限
return new User(user.getUsername(), user.getPassword(), getUserAuthority());
}
// 權(quán)限
private List<GrantedAuthority> getUserAuthority() {
return new ArrayList<>();
}
}再來說下前端,先配置跨域
module.exports = {
devServer: {
host: '0.0.0.0', // 可以忽略不寫
port: 8080, // 它是用來修改你打開后的端口號的
open: true, // 值為 true的話,項(xiàng)目啟動時自動打開到瀏覽器里邊, false不會打開
proxy: {
'/api': {
target: 'http://localhost:82', // 跨域請求的公共地址
ws: false, // 也可以忽略不寫,不寫不會影響跨域
changeOrigin: true, // 是否開啟跨域,值為 true 就是開啟, false 不開啟
pathRewrite: {
'^/api': ''// 注冊全局路徑, 但是在你請求的時候前面需要加上 /api
}
}
}
}
}配置axios,因?yàn)榕渲昧丝缬?,這個時候可以直接寫api了
import axios from 'axios'
const request = axios.create({
baseURL: '/api' // 因?yàn)榕渲每缬蛄?
})
// 下面這是攔截器,攔截請求,自動加token令牌
request.interceptors.request.use(
config => {
config.headers.token = `${localStorage.getItem('token')}`
return config
}
)
export default request說下如何請求前端登錄接口POST請求
登錄接口就是login,傳入username和password就可以了
export const Login = function (data) {
return request({
method: 'post',
url: 'login',
data: qs.stringify(data)
})
}到此這篇關(guān)于vue2+springsecurity權(quán)限系統(tǒng)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)vue springsecurity權(quán)限內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于vuepress部署出現(xiàn)樣式的問題及解決
這篇文章主要介紹了關(guān)于vuepress部署出現(xiàn)樣式的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
element-ui中導(dǎo)航組件menu的一個屬性:default-active說明
這篇文章主要介紹了element-ui中導(dǎo)航組件menu的一個屬性:default-active說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05
vue3+ts+vite使用el-table表格渲染記錄重復(fù)情況
這篇文章主要給大家介紹了關(guān)于vue3+ts+vite使用el-table表格渲染記錄重復(fù)情況的相關(guān)資料,我們可以通過合并渲染、數(shù)據(jù)緩存或虛擬化等技術(shù)來減少重復(fù)渲染的次數(shù),文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12
vue2封裝webSocket的實(shí)現(xiàn)(開箱即用)
在Vue2中,可以使用WebSocket實(shí)時通信,本文主要介紹了vue2封裝webSocket的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08
Vue3中使用Element-Plus的el-upload組件限制只上傳一個文件的功能實(shí)現(xiàn)
在 Vue 3 中使用 Element-Plus 的 el-upload 組件進(jìn)行文件上傳時,有時候需要限制只能上傳一個文件,本文將介紹如何通過配置 el-upload 組件實(shí)現(xiàn)這個功能,讓你的文件上傳變得更加簡潔和易用,需要的朋友可以參考下2023-10-10

