重磅推薦:一款功能強(qiáng)大、非常全面的Java權(quán)限認(rèn)證框架!

來源:blog.csdn.net/qq_40058629/article/
details/116692302
主要是Shiro、Security配置繁瑣,這個(gè)簡單易上手
官網(wǎng)地址
https://sa-token.dev33.cn/doc/index.html#/
主要是Shiro、Security配置繁瑣,這個(gè)簡單易上手

這是他的大致功能點(diǎn),今天我們搞點(diǎn)基礎(chǔ)的
springBoot 集成sa-token 并實(shí)現(xiàn)登錄的驗(yàn)證和權(quán)限的鑒定
首先導(dǎo)入maven坐標(biāo)
導(dǎo)入redis主要是sa-token使用內(nèi)存來存取token的,使用redis第三方來做到重啟項(xiàng)目token不丟,只需導(dǎo)入sa-token-redis的maven即可,不需要手動(dòng)get,set
<!-- Sa-Token 權(quán)限認(rèn)證, 在線文檔:http://sa-token.dev33.cn/ -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.25.0</version>
</dependency>
<!-- sa-token整合redis (使用jdk默認(rèn)序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis</artifactId>
<version>1.25.0</version>
</dependency>
yml配置文件配一下
server:
port: 8010
spring:
servlet:
multipart:
enabled: true
location: C:/var/guoheng/picture/
max-file-size: 10MB
max-request-size: 10MB
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/fire_control?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
######### druid連接池配置 #########
druid:
# 連接池建立時(shí)創(chuàng)建的初始化連接數(shù)
initial-size: 1
# 連接池中最大的活躍連接數(shù)
max-active: 20
# 連接池中最小的活躍連接數(shù)
min-idle: 1
# 連接時(shí)最大等待時(shí)間,單位毫秒。配置了maxWait之后,缺省啟用公平鎖,并發(fā)效率會(huì)有所下降,如果需要可以通過配置useUnfairLock屬性為true使用非公平鎖。
max-wait: 60000
# 是否緩存preparedStatement,也就是PSCache。PSCache對支持游標(biāo)的數(shù)據(jù)庫性能提升巨大,比如說oracle。在mysql下建議關(guān)閉。
pool-prepared-statements: false
# 指定每個(gè)連接上PSCache的大小,要啟用PSCache,必須配置大于0,當(dāng)大于0時(shí),poolPreparedStatements自動(dòng)觸發(fā)修改為true。在Druid中,不會(huì)存在Oracle下PSCache占用內(nèi)存過多的問題,可以把這個(gè)數(shù)值配置大一些,比如說100。
max-pool-prepared-statement-per-connection-size: -1
# 用來檢測連接是否有效的sql,要求是一個(gè)查詢語句。如果validationQuery為null,testOnBorrow、testOnReturn、testWhileIdle都不會(huì)其作用。(不同數(shù)據(jù)庫不同)
validation-query: SELECT 'x'
# 指定連接校驗(yàn)查詢的超時(shí)時(shí)間,單位:秒。
validation-query-timeout: 1
# 是否在獲得連接后檢測其可用性,連接時(shí)執(zhí)行validationQuery檢測連接是否有效,做了這個(gè)配置會(huì)降低性能。
test-on-borrow: false
# 是否在連接放回連接池后檢測其可用性,做了這個(gè)配置會(huì)降低性能。
test-on-return: false
# 是否在連接空閑一段時(shí)間后檢測其可用性,建議配置為true,不影響性能,并且保證安全性。申請連接的時(shí)候檢測,如果空閑時(shí)間大于timeBetweenEvictionRunsMillis,執(zhí)行validationQuery檢測連接是否有效。
test-while-idle: true
# 配置間隔多久才進(jìn)行一次檢測,檢測需要關(guān)閉的空閑連接,單位是毫秒。
time-between-eviction-runs-millis: 60000
# 配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒。
min-evictable-idle-time-millis: 300000
# 登陸超時(shí)時(shí)間,單位是秒。
login-timeout: 3
# 查詢超時(shí)時(shí)間,單位是秒。
query-timeout: 3
# 事務(wù)查詢超時(shí)時(shí)間,單位是秒。
transaction-query-timeout: 60
# 異步關(guān)閉連接。
async-close-connection-enable: true
# 屬性類型是字符串,通過別名的方式配置擴(kuò)展插件,常用的插件有:監(jiān)控統(tǒng)計(jì)用的filter:stat,日志用的filter:log4j,防御sql注入的filter:wall
filters: stat
########## StatViewServlet監(jiān)控配置 ##########
stat-view-servlet:
login-username: guoheng
login-password: guoheng
allow:
deny:
aop:
auto: true
################### redis配置 ###################
redis:
host: 127.0.0.1
port: 6379
password:
jedis:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
time-between-eviction-runs: 30000
################### sa-token配置 ###################
sa-token:
# token名稱 (同時(shí)也是cookie名稱)
token-name: satoken
# token有效期,單位s 默認(rèn)30天, -1代表永不過期
timeout: 2592000
# token臨時(shí)有效期 (指定時(shí)間內(nèi)無操作就視為token過期) 單位: 秒
activity-timeout: 3600
# 是否允許同一賬號(hào)并發(fā)登錄 (為true時(shí)允許一起登錄, 為false時(shí)新登錄擠掉舊登錄)
is-concurrent: true
# 在多人登錄同一賬號(hào)時(shí),是否共用一個(gè)token (為true時(shí)所有登錄共用一個(gè)token, 為false時(shí)每次登錄新建一個(gè)token)
is-share: false
# token風(fēng)格
token-style: simple-uuid
# 是否輸出操作日志
is-log: false
mybatis:
mapper-locations: classpath*:mapper/*.xml
接下來是很重要的兩個(gè)sa-token的config(使用過濾器的路由鑒權(quán))
PS:攔截器鑒權(quán)N多坑,不傳satoken也能訪問接口
特別注意路由一定要有區(qū)分性,例如:/user和/user/{id} 這種方式satoken框架認(rèn)為是同一個(gè)路由?。?dǎo)致路由鑒權(quán)將兩個(gè)權(quán)限碼合并認(rèn)證
package com.demo.app.config.satoken;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import result.Result;
import java.util.Arrays;
/**
* @program: fire
* @description:
* @author: fbl
* @create: 2021-08-31 12:15
**/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
/**
* 注冊 [sa-token全局過濾器]
*/
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
// 指定 [攔截路由] 與 [放行路由]
.addInclude("/**").addExclude()
// 認(rèn)證函數(shù): 每次請求執(zhí)行
.setAuth(r -> {
System.out.println("---------- sa全局認(rèn)證");
SaRouter.match(Arrays.asList("/**"), Arrays.asList(
"/login",
"/druid/**",
"/default/**",
"/",
"/swagger-ui.html",
"/swagger-resources/**",
"swagger/**",
"/webjars/**",
"/swagger-ui.html/*",
"/swagger-resources",
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/**/*.svg",
"/**/*.ico",
"/**/*.png",
"/**/*.jpg",
"/**/*.xlsx",
"/**/*.docx",
"/**/*.pdf",
"/webSocket/**",
"/*/api-docs",
"/v2/api-docs-ext"
), StpUtil::checkLogin);
// 路由一定要有區(qū)分性
SaRouter.match("/user", () -> StpUtil.checkPermission("0001"));
SaRouter.match("/user/get/{id}", () -> StpUtil.checkPermission("001101"));
})
// 異常處理函數(shù):每次認(rèn)證函數(shù)發(fā)生異常時(shí)執(zhí)行此函數(shù)
.setError(e -> {
return Result.failure(e.getMessage());
})
// 前置函數(shù):在每次認(rèn)證函數(shù)之前執(zhí)行
.setBeforeAuth(r -> {
// ---------- 設(shè)置一些安全響應(yīng)頭 ----------
SaHolder.getResponse()
// 服務(wù)器名稱
.setServer("sa-server")
// 是否可以在iframe顯示視圖:DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
.setHeader("X-Frame-Options", "SAMEORIGIN")
// 是否啟用瀏覽器默認(rèn)XSS防護(hù): 0=禁用 | 1=啟用 | 1; mode=block 啟用, 并在檢查到XSS攻擊時(shí),停止渲染頁面
.setHeader("X-Frame-Options", "1; mode=block")
// 禁用瀏覽器內(nèi)容嗅探
.setHeader("X-Content-Type-Options", "nosniff")
;
});
}
}
這里是設(shè)置登錄用戶權(quán)限和角色的地方(從權(quán)限\角色表中查詢放置),這里我只校驗(yàn)了權(quán)限,沒有校驗(yàn)角色
package com.demo.app.config.satoken;
import cn.dev33.satoken.stp.StpInterface;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.demo.app.mapper.permission.PermissionMapper;
import com.demo.app.mapper.permission.RolePermissionMapper;
import com.demo.app.mapper.role.RoleMapper;
import com.demo.app.mapper.user.UserMapper;
import com.demo.app.mapper.user.UserRoleMapper;
import model.entity.sys.RolePermission;
import model.entity.sys.SysPermission;
import model.entity.sys.SysRole;
import model.entity.sys.UserRole;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
* @program: fire
* @description: 用戶登錄賦予相應(yīng)權(quán)限
* @author: fbl
* @create: 2021-08-31 13:07
**/
@Component
public class StpInterfaceImpl implements StpInterface {
@Autowired
UserMapper userMapper;
@Autowired
UserRoleMapper userRoleMapper;
@Autowired
RoleMapper roleMapper;
@Autowired
PermissionMapper permissionMapper;
@Autowired
RolePermissionMapper rolePermissionMapper;
@Override
public List<String> getPermissionList(Object userId, String s) {
// 用戶存在,查找角色
QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
userRoleQueryWrapper.eq("user_id", userId);
List<UserRole> userRoles = userRoleMapper.selectList(userRoleQueryWrapper);
// 角色查找權(quán)限
QueryWrapper<RolePermission> rolePermissionQueryWrapper = new QueryWrapper<>();
rolePermissionQueryWrapper.in("role_id", userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList()));
List<RolePermission> rolePermissions = rolePermissionMapper.selectList(rolePermissionQueryWrapper);
QueryWrapper<SysPermission> permissionQueryWrapper = new QueryWrapper<>();
permissionQueryWrapper.in("id", rolePermissions.stream().map(RolePermission::getPermissionId).distinct().collect(Collectors.toList()));
List<SysPermission> sysPermissions = permissionMapper.selectList(permissionQueryWrapper);
List<String> permissions = sysPermissions.stream().map(SysPermission::getCode).distinct().collect(Collectors.toList());
return permissions;
}
@Override
public List<String> getRoleList(Object userId, String s) {
// 用戶存在,查找角色
QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
userRoleQueryWrapper.eq("user_id", userId);
List<UserRole> userRoles = userRoleMapper.selectList(userRoleQueryWrapper);
// 查詢角色
QueryWrapper<SysRole> sysRoleQueryWrapper = new QueryWrapper<SysRole>().in("id", userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList()));
List<SysRole> sysRoles = roleMapper.selectList(sysRoleQueryWrapper);
List<String> roleNames = sysRoles.stream().map(SysRole::getRoleName).distinct().collect(Collectors.toList());
return roleNames;
}
}
打這里認(rèn)證鑒權(quán)就完成了,快把,趕緊來測試一下吧。
學(xué)習(xí)資料:Java進(jìn)階視頻資源
還有一個(gè)配置文件沖突的問題,之前我在webMvc里面配置的有靜態(tài)文件讀取和跨域等,與satoken的配置起了沖突,我修改了自己的配置文件
package com.demo.app.config.webmvc;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 類功能描述: CorsConfig
*
* @author Eternal
* @date 2019-11-26 15:11
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Value("${spring.servlet.multipart.location}")
private String uploadFileUrl;
/**
* 跨域配置
*
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "GET", "PUT", "DELETE", "OPTIONS")
.maxAge(3600)
// 是否允許發(fā)送Cookie
.allowCredentials(true)
.allowedHeaders("*");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 靜態(tài)文件
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
// swagger
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
// 上傳文件
registry.addResourceHandler("/file/**").addResourceLocations("file:/" + uploadFileUrl);
}
}
測試一下

拿到token放進(jìn)header里取請求需要權(quán)限的接口
沒有權(quán)限
擁有權(quán)限

還在用Spring Security?推薦你一款使用簡單、功能強(qiáng)大的權(quán)限認(rèn)證框架

