1、pom 依赖引入
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
2、基础配置
properties 文件
rsaPrivateKey=MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIxgS3b5J9IRYlvEFIEeDeQCGkOI5pT+Nl3wNe0fdWIiw36g4sH1l2sLuTZ6bew9YRLIapude6ORGZF5UfNy9cor3N7n3ew/fXCEKVRC6Kg+cREm1rqyMjDc9NtfksXG4RGf7GNeoTmUDVStsnXvoLnzvrE7FvbB12XKfhTQDnSZAgMBAAECgYBcyET45SP5x/2/87EtymSaAP3FB5aIgiIDIwMxsKpQa/PVHZfjZWVonn4T0QYYsFUaKhe0tXmEGiLRMWQGSkTEGfZ5l7uRmrNZ0Nk9asu4/fyjwZNHYDDGAELU5R4WgLvO09PdVLG/uyIxXh9qg9y9OpYM4KoATnsH7t7TPdI5gQJBAMnB6nz18BKSsHX7qDkWWpxZUOZmcKIsZoaDlz1NkoAKrOuH8TYc75uwLhR17nOOI9kO+10FKlYQ/5+yUiQIE+kCQQCyHcU/0mlvvByrJsYJMDUMtDk5/BtCWD6UZan/X1GH2EHx1W5LuL+wyIr6CUrY5G3osVU5ZvLly4zTFRQHr10xAkEAqFJT4zT7uUMQXR47VoVDyzTovY+xYFtSnd6jCs3w70n4wfeEUfUKIgV2LDPHYDixx6EsLIrmqy87VGxdAxqKIQJAe2bOyvnfXK9KeXWCjMkeZ+/RGhBFXoC+0pdg4PHMDb7RaVgCc2nLPRKj3rljZsNUNnvt3LgrnvOYXIHk/7IKcQJAGakaB+211CbKnIHtjxSsg07EiM3dZVA1jrXTbJ6NuhURZTIOR0YJsVdWoEbwBLv/STTvc7+G+wo1yuzzBAse+w==
rsaPublicKey=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMYEt2+SfSEWJbxBSBHg3kAhpDiOaU/jZd8DXtH3ViIsN+oOLB9ZdrC7k2em3sPWESyGqbnXujkRmReVHzcvXKK9ze593sP31whClUQuioPnERJta6sjIw3PTbX5LFxuERn+xjXqE5lA1UrbJ176C5876xOxb2wddlyn4U0A50mQIDAQAB
# AES密码加密私钥(Base64加密)
encryptAESKey=V2FuZzkyNjQ1NGRTQkFQSUpXVA==
# JWT认证加密私钥(Base64加密)
encryptJWTKey=U0JBUElKV1RkV2FuZzkyNjQ1NA==
# AccessToken过期时间-5分钟-5*60(秒为单位)
accessTokenExpireTime=300
# RefreshToken过期时间-30分钟-30*60(秒为单位)
refreshTokenExpireTime=1800
# Shiro缓存过期时间-5分钟-5*60(秒为单位)(一般设置与AccessToken过期时间一致)
shiroCacheExpireTime=10
# 文件缓存地址
fileCachePath=D:\\download\\kmair\\contract\\file_backup
loginUrl=/user/loginByUsernameAndPassword
读取配置类(@Data 是 lombok 注解)
@Data
public class SysProperties {
private String rsaPublicKey;
private String rsaPrivateKey;
private String encryptAESKey;
private String encryptJWTKey;
private int accessTokenExpireTime;
private int refreshTokenExpireTime;
private int shiroCacheExpireTime;
private String fileCachePath;
private String loginUrl;
}
@Data
@EnableAutoConfiguration
@Configuration
@PropertySource("classpath:config.properties")
public class SysConfig {
@Value("${rsaPublicKey}")
private String rsaPublicKey;
@Value("${rsaPrivateKey}")
private String rsaPrivateKey;
@Value("${encryptAESKey}")
private String encryptAESKey;
@Value("${encryptJWTKey}")
private String encryptJWTKey;
@Value("${accessTokenExpireTime}")
private int accessTokenExpireTime;
@Value("${refreshTokenExpireTime}")
private int refreshTokenExpireTime;
@Value("${shiroCacheExpireTime}")
private int shiroCacheExpireTime;
@Value("${fileCachePath}")
private String fileCachePath;
@Value("${loginUrl}")
private String loginUrl;
@Bean(value = "sysProperties",name = "sysProperties")
public SysProperties init(){
SysProperties sysProperties = new SysProperties();
sysProperties.setRsaPublicKey(rsaPublicKey);
sysProperties.setRsaPrivateKey(rsaPrivateKey);
sysProperties.setEncryptAESKey(this.encryptAESKey);
sysProperties.setEncryptJWTKey(this.encryptJWTKey);
sysProperties.setAccessTokenExpireTime(this.accessTokenExpireTime);
sysProperties.setRefreshTokenExpireTime(this.refreshTokenExpireTime);
sysProperties.setShiroCacheExpireTime(this.shiroCacheExpireTime);
sysProperties.setFileCachePath(fileCachePath);
sysProperties.setLoginUrl(loginUrl);
return sysProperties;
}
}
3、response 工具类
这里有一个坑要注意避免,部分版本的 fastjson 在处理数据返回的时候,会调用 response 的 getWrite 方法,所以我们这里需要调用 getOutputstream 方法,不然会出现报错,提示 getWrite 已经被调用过,我的 fastjson 版本是 1.2.70
/**
* @author Mr.Wen
* @version 1.0
* @date 2021-08-11 15:34
*/
@Slf4j
public class ResponseUtils {
public static void out(HttpServletResponse response, HttpResult result){
response.setStatus(HttpStatus.OK.value());
//统一返回的JSON数据
response.setContentType("application/json; charset=UTF-8");
try (ServletOutputStream out = response.getOutputStream()) {
out.write(JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
log.error("输出数据异常", e);
}
}
}
4、常量类
5、用户信息类重写
6、用户信息查询类重写
这里要实现查询用户信息,关键就是实现 UserDetailsService 接口,内部实现,根据自己的需求来写
/**
* @author Mr.Wen
* @version 1.0
* @date 2021-08-11 15:05
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Resource
private UserDataMapper userDataMapper;
@Resource
private SysRoleMapper sysRoleMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserData userData = userDataMapper.selectByWorkId(username);
List<SysRole> sysRoles = sysRoleMapper.selectByUserId(userData.getId());
List<String> permissions = new ArrayList<>();
for(SysRole sysRole:sysRoles){
permissions.add(sysRole.getRoleCode());
}
return new SecurityUserDetails(userData.getUsername(),userData.getPassword(),permissions);
}
}
7、授权过滤器,处理 token
我使用了双 token,这里也是根据自己的认真逻辑修改就好了
8、密码处理器
9、security 运行配置
10、登录,退出接口
这个类的 login 方法涉及到一个加密解密的算法,前端传递的用户密码信息都是用这个算法加密解密的,换成自己的实现即可;根据用户令牌获取用户权限的接口自己实现就好;退出没有调用 spring security 的方法,自己实现了一个,另一种方法就是使用默认的退出登录的接口,然后自己实现一个 LogoutSuccessHandler,在这里面处理退出的逻辑即可
11、总结
spring security 可以自定义 loginSuccessHandler,logoutSuccessHandler 还有对应的失败的以及其他的 handler,总的来说功能还是比较强大,和 shiro 相比,二者能实现功能都差不多,但是 spring security 依赖于 spring 容器,而且 spring security 对新手不太友好,总的来说,可以用 shiro 就没必要使用 spring security。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于