【权限管理平台】项目开发Day—02
🏡 博客首页:派 大 星
⛳️ 欢迎关注 🐳 点赞 🎒 收藏 ✏️ 留言
🎢 本文由派大星原创编撰
🚧 系列专栏:项目从0搭建
🎈 本系列项目从设计到实现源码全部开源免费学习使用,一起追向理想,欢迎各位大佬监督打卡开发!
今日项目搭建进度
🍌权限数据设计&接口设计
🍇 权限数据设计
由于这部分数据的设计设计与添加过于耗费时间(其实是因为懒
),我选择在开发的过程中等这部分接口编码完毕之后,通过Swagger文档按需添加。
🍑 接口设计
在平时做开发时,习惯性的把我们编写的接口称之为Api
,所以,这次索性就把本项目的接口设计为/api/xxx/xxx
(其实根本算不上设计 ♨️ )。
🍍实际编码
🍔 Swagger相关配置
Swagger
是一个规范和完整的框架,用于生成、描述、调用和可视化 RestFul
风格的 Web
服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。
导入依赖
<!--swagger2 依赖-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
相关配置
@Configuration
public class SwaggerConfig {
@Value("${swagger2.enable}")
private boolean enable;
@Bean
public Docket docket(){
/*
* 这是为了我们在使用swagger 测试接口时添加头部信息(token)
* 登录之后返回Token信息,将Token添加进去,用于访问其他需要某些权限\角色的接口
* */
List<Parameter> pars = new ArrayList<Parameter>();
ParameterBuilder tokenPar = new ParameterBuilder();
tokenPar.name("authorization").description("请输入Token信息")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false);
/*
*多个的时候 就直接添加到 pars就可以了
* */
pars.add(tokenPar.build());
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.pdx.controller"))
.paths(PathSelectors.any())
.build()
.globalOperationParameters(pars)
.enable(enable);
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("派大星权限管理平台")
.description("派大星权限管理平台")
.termsOfServiceUrl("")
.version("1.0")
.build();
}
}
🍰 Shiro框架基础搭建相关配置
那么什么是Shiro
呢?下面我们简单了解一下这个安全框架:
Shiro
框架是Apache
下的一款Java安全框架,具有和SpringSecurity
一样的效果,相较于SpringSecurity
而Shiro
的特点会更加突出:
- 便捷
- 易上手
- 支持注解开发
🍕 Shiro主要功能:
三个核心组件:Subject
SecurityManager
和 Realms
Subject:
即“当前操作用户”。但是,在Shiro
中,Subject
这一概念并不仅仅指人,也可以是第三方进程、后台帐户或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。SecurityManager:
它是Shiro
框架的核心,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。Realm:
Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro
会从应用配置的Realm
中查找用户及其权限信息。
如果你还不了解shiro
的认证机制,请移步: 派大星十分钟带你了解Shiro的认证机制
🍫 了解 Jwt
JWT
(全称:Json Web Token
)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
Jwt的数据结构
Jwt
一般是字符串,分为三部分,并且每部分中间用"."
隔开:
xxxxx.yyyyy.zzzzz
Jwt包括哪三部分呢?
- Header
JWT
第一部分是头部分,它是一个描述JWT元数据的Json
对象,通常如下所示。
{
"alg": "HS256",
"typ": "JWT"
}
alg
属性表示签名使用的算法,默认为HMAC SHA256
(写为HS256
),typ
属性表示令牌的类型,JWT
令牌统一写为JWT
。
- Payload
JWT
第二部分是Payload
,也是一个Json
对象,除了包含需要传递的数据,还有七个默认的字段供选择。
分别是,iss
:发行人、exp
:到期时间、sub
:主题、aud
:用户、nbf
:在此之前不可用、iat
:发布时间、jti
:JWT ID
用于标识该JWT
.
- Signature
那么它是怎么生成的呢?首先需要指定一个secret
,该secret
仅仅保存在服务器中,保证不能让其他用户知道。然后使用Header指定的算法对Header
和Payload
进行计算,然后就得出一个签名哈希。也就是Signature
。
🍨 优点
json
格式的通用性,所以JWT
可以跨语言支持,比如Java、JavaScript、PHP、Node
等等。- 可以利用
Payload
存储一些非敏感的信息。 - 便于传输,
JWT
结构简单,字节占用小。 - 不需要在服务端保存会话信息,易于应用的扩展。
🍒 Shiro配置实际操作
导入依赖
<!--shiro 依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
自定义Realm类
@Slf4j
public class CustomRealm extends AuthorizingRealm {
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof CustomUsernamePasswordToken;
}
/**
* 授权机制
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
/**
* 认证机制
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
CustomUsernamePasswordToken usernamePasswordToken = (CustomUsernamePasswordToken) token;
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(usernamePasswordToken.getPrincipal(), usernamePasswordToken.getCredentials(), getName());
return info;
}
}
自定义Shiro默认加密方式
@Slf4j
public class CustomHashedCredentialsMatcher extends HashedCredentialsMatcher {
@Autowired
private RedisService redisService;
/**
* 加密匹配
* @param token
* @param info
* @return
*/
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
CustomUsernamePasswordToken usernamePasswordToken = (CustomUsernamePasswordToken) token;
String accessToken = (String) usernamePasswordToken.getCredentials();
String userId = JwtTokenUtil.getUserId(accessToken);
log.info("doCredentialsMatch.....userId=>{}",userId);
//判断用户是否被删除
if (redisService.hasKey(Constant.DELETE_USER_KEY+userId)){
throw new BusinessException(BaseResponseCode.ACCOUNT_HAS_DELETE_ERROR);
}
//判断用户是否被锁定
if (redisService.hasKey(Constant.ACCOUNT_LOCK_KEY+userId)){
throw new BusinessException(BaseResponseCode.ACCOUNT_LOCKED);
}
//判断用户是否退出登录
if (redisService.hasKey(Constant.JWT_ACCESS_TOKEN_BLACKLIST+userId)){
throw new BusinessException(BaseResponseCode.TOKEN_ERROR);
}
//校验Token
if (!JwtTokenUtil.validateToken(accessToken)){
throw new BusinessException(BaseResponseCode.TOKEN_PAST_DUE);
}
return true;
}
}
自定义UsernamePasswordToken 类
public class CustomUsernamePasswordToken extends UsernamePasswordToken {
private String jwtToken;
public CustomUsernamePasswordToken(String jwtToken){
this.jwtToken = jwtToken;
}
@Override
public Object getPrincipal() {
return jwtToken;
}
@Override
public Object getCredentials() {
return jwtToken;
}
}
新鲜出炉的代码将会及时更新到Gitee
仓库
以上代码属于部分实现,想要了解全部配置请移步: 派大星的Gitee仓库
今天的工作量就进行到这里!希望大佬们可以监督派大星一步步从0搭建该平台!