Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
IEQEFCR
halo
提交
7c6708d5
H
halo
项目概览
IEQEFCR
/
halo
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
H
halo
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
7c6708d5
编写于
4月 29, 2019
作者:
J
johnniang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Complete token authentication
上级
e580f4fa
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
198 addition
and
45 deletion
+198
-45
src/main/java/run/halo/app/cache/InMemoryCacheStore.java
src/main/java/run/halo/app/cache/InMemoryCacheStore.java
+1
-0
src/main/java/run/halo/app/controller/admin/api/AdminController.java
...va/run/halo/app/controller/admin/api/AdminController.java
+4
-18
src/main/java/run/halo/app/model/dto/StatisticDTO.java
src/main/java/run/halo/app/model/dto/StatisticDTO.java
+2
-2
src/main/java/run/halo/app/security/filter/AdminAuthenticationFilter.java
...n/halo/app/security/filter/AdminAuthenticationFilter.java
+20
-4
src/main/java/run/halo/app/security/util/SecurityUtils.java
src/main/java/run/halo/app/security/util/SecurityUtils.java
+50
-0
src/main/java/run/halo/app/service/AdminService.java
src/main/java/run/halo/app/service/AdminService.java
+7
-3
src/main/java/run/halo/app/service/UserService.java
src/main/java/run/halo/app/service/UserService.java
+21
-3
src/main/java/run/halo/app/service/impl/AdminServiceImpl.java
...main/java/run/halo/app/service/impl/AdminServiceImpl.java
+72
-15
src/main/java/run/halo/app/service/impl/UserServiceImpl.java
src/main/java/run/halo/app/service/impl/UserServiceImpl.java
+21
-0
未找到文件。
src/main/java/run/halo/app/cache/InMemoryCacheStore.java
浏览文件 @
7c6708d5
...
...
@@ -91,6 +91,7 @@ public class InMemoryCacheStore extends StringCacheStore {
Assert
.
hasText
(
key
,
"Cache key must not be blank"
);
cacheContainer
.
remove
(
key
);
log
.
debug
(
"Removed key: [{}]"
,
key
);
}
/**
...
...
src/main/java/run/halo/app/controller/admin/api/AdminController.java
浏览文件 @
7c6708d5
...
...
@@ -4,15 +4,11 @@ import io.swagger.annotations.ApiOperation;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.bind.annotation.*
;
import
run.halo.app.cache.lock.CacheLock
;
import
run.halo.app.exception.BadRequestException
;
import
run.halo.app.model.dto.CountDTO
;
import
run.halo.app.model.dto.StatisticDTO
;
import
run.halo.app.model.params.LoginParam
;
import
run.halo.app.security.context.SecurityContextHolder
;
import
run.halo.app.security.filter.AdminAuthenticationFilter
;
import
run.halo.app.security.token.AuthToken
;
import
run.halo.app.service.AdminService
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.validation.Valid
;
/**
...
...
@@ -39,7 +35,7 @@ public class AdminController {
*/
@GetMapping
(
"counts"
)
@ApiOperation
(
"Gets count info"
)
public
Count
DTO
getCount
()
{
public
Statistic
DTO
getCount
()
{
return
adminService
.
getCount
();
}
...
...
@@ -52,17 +48,7 @@ public class AdminController {
@PostMapping
(
"logout"
)
@ApiOperation
(
"Logs out (Clear session)"
)
@CacheLock
public
void
logout
(
HttpServletRequest
request
)
{
adminService
.
clearAuthentication
();
// Check if the current is logging in
boolean
authenticated
=
SecurityContextHolder
.
getContext
().
isAuthenticated
();
if
(!
authenticated
)
{
throw
new
BadRequestException
(
"You haven't logged in yet, so you can't log out"
);
}
request
.
getSession
().
removeAttribute
(
AdminAuthenticationFilter
.
ADMIN_SESSION_KEY
);
log
.
info
(
"You have been logged out, Welcome to you next time!"
);
public
void
logout
()
{
adminService
.
clearToken
();
}
}
src/main/java/run/halo/app/model/dto/
Count
DTO.java
→
src/main/java/run/halo/app/model/dto/
Statistic
DTO.java
浏览文件 @
7c6708d5
...
...
@@ -3,13 +3,13 @@ package run.halo.app.model.dto;
import
lombok.Data
;
/**
*
Count output
DTO.
*
Statistic
DTO.
*
* @author johnniang
* @date 3/19/19
*/
@Data
public
class
Count
DTO
{
public
class
Statistic
DTO
{
private
long
postCount
;
...
...
src/main/java/run/halo/app/security/filter/AdminAuthenticationFilter.java
浏览文件 @
7c6708d5
...
...
@@ -14,6 +14,7 @@ import run.halo.app.security.authentication.AuthenticationImpl;
import
run.halo.app.security.context.SecurityContextHolder
;
import
run.halo.app.security.context.SecurityContextImpl
;
import
run.halo.app.security.support.UserDetail
;
import
run.halo.app.security.util.SecurityUtils
;
import
run.halo.app.service.UserService
;
import
javax.servlet.FilterChain
;
...
...
@@ -37,6 +38,16 @@ public class AdminAuthenticationFilter extends AbstractAuthenticationFilter {
*/
public
final
static
String
ADMIN_SESSION_KEY
=
"halo.admin.session"
;
/**
* Access token cache prefix.
*/
public
final
static
String
TOKEN_ACCESS_CACHE_PREFIX
=
"halo.admin.access.token."
;
/**
* Refresh token cache prefix.
*/
public
final
static
String
TOKEN_REFRESH_CACHE_PREFIX
=
"halo.admin.refresh.token."
;
/**
* Admin token header name.
*/
...
...
@@ -82,20 +93,25 @@ public class AdminAuthenticationFilter extends AbstractAuthenticationFilter {
if
(
StringUtils
.
isNotBlank
(
token
))
{
//
Valid the token
Optional
<
UserDetail
>
optionalUserDetail
=
cacheStore
.
getAny
(
token
,
UserDetail
.
class
);
//
Get user id from cache
Optional
<
Integer
>
optionalUserId
=
cacheStore
.
getAny
(
SecurityUtils
.
buildTokenAccessKey
(
token
),
Integer
.
class
);
if
(!
optionalUser
Detail
.
isPresent
())
{
if
(!
optionalUser
Id
.
isPresent
())
{
getFailureHandler
().
onFailure
(
request
,
response
,
new
AuthenticationException
(
"The token has been expired or not exist"
).
setErrorData
(
token
));
return
;
}
UserDetail
userDetail
=
optionalUserDetail
.
get
();
// Get the user
User
user
=
userService
.
getById
(
optionalUserId
.
get
());
// Build user detail
UserDetail
userDetail
=
new
UserDetail
(
user
);
// Set security
SecurityContextHolder
.
setContext
(
new
SecurityContextImpl
(
new
AuthenticationImpl
(
userDetail
)));
filterChain
.
doFilter
(
request
,
response
);
return
;
}
...
...
src/main/java/run/halo/app/security/util/SecurityUtils.java
0 → 100644
浏览文件 @
7c6708d5
package
run.halo.app.security.util
;
import
org.springframework.lang.NonNull
;
import
org.springframework.util.Assert
;
import
run.halo.app.model.entity.User
;
import
static
run
.
halo
.
app
.
security
.
filter
.
AdminAuthenticationFilter
.
TOKEN_ACCESS_CACHE_PREFIX
;
import
static
run
.
halo
.
app
.
security
.
filter
.
AdminAuthenticationFilter
.
TOKEN_REFRESH_CACHE_PREFIX
;
import
static
run
.
halo
.
app
.
service
.
AdminService
.
ACCESS_TOKEN_CACHE_PREFIX
;
import
static
run
.
halo
.
app
.
service
.
AdminService
.
REFRESH_TOKEN_CACHE_PREFIX
;
/**
* Security utilities.
*
* @author johnniang
* @date 19-4-29
*/
public
class
SecurityUtils
{
private
SecurityUtils
()
{
}
@NonNull
public
static
String
buildAccessTokenKey
(
@NonNull
User
user
)
{
Assert
.
notNull
(
user
,
"User must not be null"
);
return
ACCESS_TOKEN_CACHE_PREFIX
+
user
.
getId
();
}
@NonNull
public
static
String
buildRefreshTokenKey
(
@NonNull
User
user
)
{
Assert
.
notNull
(
user
,
"User must not be null"
);
return
REFRESH_TOKEN_CACHE_PREFIX
+
user
.
getId
();
}
@NonNull
public
static
String
buildTokenAccessKey
(
@NonNull
String
accessToken
)
{
Assert
.
hasText
(
accessToken
,
"Access token must not be blank"
);
return
TOKEN_ACCESS_CACHE_PREFIX
+
accessToken
;
}
@NonNull
public
static
String
buildTokenRefreshKey
(
@NonNull
String
refreshToken
)
{
Assert
.
hasText
(
refreshToken
,
"Refresh token must not be blank"
);
return
TOKEN_REFRESH_CACHE_PREFIX
+
refreshToken
;
}
}
src/main/java/run/halo/app/service/AdminService.java
浏览文件 @
7c6708d5
package
run.halo.app.service
;
import
org.springframework.lang.NonNull
;
import
run.halo.app.model.dto.
Count
DTO
;
import
run.halo.app.model.dto.
Statistic
DTO
;
import
run.halo.app.model.params.LoginParam
;
import
run.halo.app.security.token.AuthToken
;
...
...
@@ -13,6 +13,10 @@ import run.halo.app.security.token.AuthToken;
*/
public
interface
AdminService
{
String
ACCESS_TOKEN_CACHE_PREFIX
=
"halo.admin.access_token."
;
String
REFRESH_TOKEN_CACHE_PREFIX
=
"halo.admin.refresh_token."
;
/**
* Authenticates.
*
...
...
@@ -25,7 +29,7 @@ public interface AdminService {
/**
* Clears authentication.
*/
void
clear
Authenticatio
n
();
void
clear
Toke
n
();
/**
* Get system counts.
...
...
@@ -33,5 +37,5 @@ public interface AdminService {
* @return count dto
*/
@NonNull
Count
DTO
getCount
();
Statistic
DTO
getCount
();
}
src/main/java/run/halo/app/service/UserService.java
浏览文件 @
7c6708d5
package
run.halo.app.service
;
import
org.springframework.lang.NonNull
;
import
org.springframework.lang.Nullable
;
import
run.halo.app.exception.ForbiddenException
;
import
run.halo.app.exception.NotFoundException
;
import
run.halo.app.model.entity.User
;
import
run.halo.app.model.params.UserParam
;
import
run.halo.app.service.base.CrudService
;
import
javax.servlet.http.HttpSession
;
import
java.util.Optional
;
/**
...
...
@@ -80,8 +81,8 @@ public interface UserService extends CrudService<User, Integer> {
/**
* Logins by username and password.
*
* @param key
username or email must not be blank
* @param password
password must not be blank
* @param key username or email must not be blank
* @param password password must not be blank
* @return user info
*/
@NonNull
...
...
@@ -107,4 +108,21 @@ public interface UserService extends CrudService<User, Integer> {
*/
@NonNull
User
createBy
(
@NonNull
UserParam
userParam
);
/**
* The user must not expire.
*
* @param user user info must not be null
* @throws ForbiddenException throws if the given user has been expired
*/
void
mustNotExpire
(
@NonNull
User
user
);
/**
* Checks the password is match the user password.
*
* @param user user info must not be null
* @param plainPassword plain password
* @return true if the given password is match the user password; false otherwise
*/
boolean
passwordMatch
(
@NonNull
User
user
,
@Nullable
String
plainPassword
);
}
src/main/java/run/halo/app/service/impl/AdminServiceImpl.java
浏览文件 @
7c6708d5
package
run.halo.app.service.impl
;
import
cn.hutool.core.lang.Validator
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
org.springframework.util.Assert
;
import
run.halo.app.cache.StringCacheStore
;
import
run.halo.app.exception.BadRequestException
;
import
run.halo.app.model.dto.CountDTO
;
import
run.halo.app.model.dto.StatisticDTO
;
import
run.halo.app.model.entity.User
;
import
run.halo.app.model.enums.CommentStatus
;
import
run.halo.app.model.enums.PostStatus
;
import
run.halo.app.model.params.LoginParam
;
import
run.halo.app.security.authentication.Authentication
;
import
run.halo.app.security.context.SecurityContextHolder
;
import
run.halo.app.security.token.AuthToken
;
import
run.halo.app.security.util.SecurityUtils
;
import
run.halo.app.service.*
;
import
run.halo.app.utils.HaloUtils
;
import
java.util.concurrent.TimeUnit
;
/**
* Admin service implementation.
...
...
@@ -69,42 +76,92 @@ public class AdminServiceImpl implements AdminService {
public
AuthToken
authenticate
(
LoginParam
loginParam
)
{
Assert
.
notNull
(
loginParam
,
"Login param must not be null"
);
return
null
;
if
(
SecurityContextHolder
.
getContext
().
isAuthenticated
())
{
// If the user has been logged in
throw
new
BadRequestException
(
"您已经登录,无需重复登录"
);
}
String
username
=
loginParam
.
getUsername
();
User
user
=
Validator
.
isEmail
(
username
)
?
userService
.
getByEmailOfNonNull
(
username
)
:
userService
.
getByUsernameOfNonNull
(
username
);
userService
.
mustNotExpire
(
user
);
if
(!
userService
.
passwordMatch
(
user
,
loginParam
.
getPassword
()))
{
// If the password is mismatch
throw
new
BadRequestException
(
"Username or password is incorrect"
);
}
// Generate new token
AuthToken
token
=
new
AuthToken
();
int
expiredIn
=
24
*
3600
;
token
.
setAccessToken
(
HaloUtils
.
randomUUIDWithoutDash
());
token
.
setExpiredIn
(
expiredIn
);
token
.
setRefreshToken
(
HaloUtils
.
randomUUIDWithoutDash
());
// Cache those tokens, just for clearing
cacheStore
.
putAny
(
SecurityUtils
.
buildAccessTokenKey
(
user
),
token
.
getAccessToken
(),
30
,
TimeUnit
.
DAYS
);
cacheStore
.
putAny
(
SecurityUtils
.
buildRefreshTokenKey
(
user
),
token
.
getRefreshToken
(),
30
,
TimeUnit
.
DAYS
);
// Cache those tokens with user id
cacheStore
.
putAny
(
SecurityUtils
.
buildTokenAccessKey
(
token
.
getAccessToken
()),
user
.
getId
(),
expiredIn
,
TimeUnit
.
SECONDS
);
cacheStore
.
putAny
(
SecurityUtils
.
buildTokenRefreshKey
(
token
.
getRefreshToken
()),
user
.
getId
(),
30
,
TimeUnit
.
DAYS
);
return
token
;
}
@Override
public
void
clear
Authenticatio
n
()
{
public
void
clear
Toke
n
()
{
// Check if the current is logging in
boolean
authenticated
=
SecurityContextHolder
.
getContext
().
isAuthenticated
();
Authentication
authentication
=
SecurityContextHolder
.
getContext
().
getAuthentication
();
if
(
!
authenticated
)
{
if
(
authentication
==
null
)
{
throw
new
BadRequestException
(
"You haven't logged in yet, so you can't log out"
);
}
// Get current user
User
user
=
authentication
.
getDetail
().
getUser
();
// Clear access token
cacheStore
.
getAny
(
SecurityUtils
.
buildAccessTokenKey
(
user
),
String
.
class
).
ifPresent
(
accessToken
->
{
// Delete token
cacheStore
.
delete
(
SecurityUtils
.
buildTokenAccessKey
(
accessToken
));
cacheStore
.
delete
(
SecurityUtils
.
buildAccessTokenKey
(
user
));
});
// Clear refresh token
cacheStore
.
getAny
(
SecurityUtils
.
buildRefreshTokenKey
(
user
),
String
.
class
).
ifPresent
(
refreshToken
->
{
cacheStore
.
delete
(
SecurityUtils
.
buildTokenRefreshKey
(
refreshToken
));
cacheStore
.
delete
(
SecurityUtils
.
buildRefreshTokenKey
(
user
));
});
log
.
info
(
"You have been logged out, looking forward to your next visit!"
);
}
@Override
public
Count
DTO
getCount
()
{
CountDTO
countDTO
=
new
Count
DTO
();
count
DTO
.
setPostCount
(
postService
.
countByStatus
(
PostStatus
.
PUBLISHED
));
count
DTO
.
setAttachmentCount
(
attachmentService
.
count
());
public
Statistic
DTO
getCount
()
{
StatisticDTO
statisticDTO
=
new
Statistic
DTO
();
statistic
DTO
.
setPostCount
(
postService
.
countByStatus
(
PostStatus
.
PUBLISHED
));
statistic
DTO
.
setAttachmentCount
(
attachmentService
.
count
());
// Handle comment count
long
postCommentCount
=
postCommentService
.
countByStatus
(
CommentStatus
.
PUBLISHED
);
long
sheetCommentCount
=
sheetCommentService
.
countByStatus
(
CommentStatus
.
PUBLISHED
);
long
journalCommentCount
=
journalCommentService
.
countByStatus
(
CommentStatus
.
PUBLISHED
);
count
DTO
.
setCommentCount
(
postCommentCount
+
sheetCommentCount
+
journalCommentCount
);
statistic
DTO
.
setCommentCount
(
postCommentCount
+
sheetCommentCount
+
journalCommentCount
);
long
birthday
=
optionService
.
getBirthday
();
long
days
=
(
System
.
currentTimeMillis
()
-
birthday
)
/
(
1000
*
24
*
3600
);
count
DTO
.
setEstablishDays
(
days
);
statistic
DTO
.
setEstablishDays
(
days
);
count
DTO
.
setLinkCount
(
linkService
.
count
());
statistic
DTO
.
setLinkCount
(
linkService
.
count
());
count
DTO
.
setVisitCount
(
postService
.
countVisit
()
+
sheetService
.
countVisit
());
count
DTO
.
setLikeCount
(
postService
.
countLike
()
+
sheetService
.
countLike
());
return
count
DTO
;
statistic
DTO
.
setVisitCount
(
postService
.
countVisit
()
+
sheetService
.
countVisit
());
statistic
DTO
.
setLikeCount
(
postService
.
countLike
()
+
sheetService
.
countLike
());
return
statistic
DTO
;
}
}
src/main/java/run/halo/app/service/impl/UserServiceImpl.java
浏览文件 @
7c6708d5
...
...
@@ -2,6 +2,7 @@ package run.halo.app.service.impl;
import
cn.hutool.core.lang.Validator
;
import
cn.hutool.crypto.digest.BCrypt
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.context.ApplicationEventPublisher
;
import
org.springframework.lang.NonNull
;
import
org.springframework.stereotype.Service
;
...
...
@@ -12,6 +13,7 @@ import run.halo.app.cache.lock.CacheLock;
import
run.halo.app.event.logger.LogEvent
;
import
run.halo.app.event.user.UserUpdatedEvent
;
import
run.halo.app.exception.BadRequestException
;
import
run.halo.app.exception.ForbiddenException
;
import
run.halo.app.exception.NotFoundException
;
import
run.halo.app.model.entity.User
;
import
run.halo.app.model.enums.LogType
;
...
...
@@ -205,6 +207,25 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
return
create
(
user
);
}
@Override
public
void
mustNotExpire
(
User
user
)
{
Assert
.
notNull
(
user
,
"User must not be null"
);
Date
now
=
DateUtils
.
now
();
if
(
user
.
getExpireTime
()
!=
null
&&
user
.
getExpireTime
().
after
(
now
))
{
long
seconds
=
TimeUnit
.
MILLISECONDS
.
toSeconds
(
user
.
getExpireTime
().
getTime
()
-
now
.
getTime
());
// If expired
throw
new
ForbiddenException
(
"You have been temporarily disabled,please try again "
+
HaloUtils
.
timeFormat
(
seconds
)
+
" later"
).
setErrorData
(
seconds
);
}
}
@Override
public
boolean
passwordMatch
(
User
user
,
String
plainPassword
)
{
Assert
.
notNull
(
user
,
"User must not be null"
);
return
!
StringUtils
.
isBlank
(
plainPassword
)
&&
BCrypt
.
checkpw
(
plainPassword
,
user
.
getPassword
());
}
@Override
@CacheLock
public
User
create
(
User
user
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录