修改用户名
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
package com.arrokoth.standalone.authorization.controller;
|
||||||
|
|
||||||
|
import com.arrokoth.basic.properties.SecurityWebProperties;
|
||||||
|
import com.arrokoth.basic.request.LoginRequest;
|
||||||
|
import com.arrokoth.basic.response.Token;
|
||||||
|
import com.arrokoth.basic.service.AuthorizationService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RequestMapping
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LoginController {
|
||||||
|
|
||||||
|
private final AuthorizationService authorizationService;
|
||||||
|
private final AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
@Operation(summary = "登录", description = "获取登录Token信息")
|
||||||
|
@PostMapping(SecurityWebProperties.AXIOS_LOGIN_PROCESSING_URL)
|
||||||
|
public Token homeLogin(@Valid @RequestBody LoginRequest loginRequest) {
|
||||||
|
UsernamePasswordAuthenticationToken passwordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
|
||||||
|
Authentication authenticate = authenticationManager.authenticate(passwordAuthenticationToken);
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authenticate);
|
||||||
|
return authorizationService.login(loginRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import jakarta.servlet.ServletException;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
@@ -15,8 +16,9 @@ import org.springframework.stereotype.Component;
|
|||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class JwtRequestFilter extends OncePerRequestFilter {
|
public class JwtRequestFilter extends OncePerRequestFilter {
|
||||||
@@ -26,47 +28,119 @@ public class JwtRequestFilter extends OncePerRequestFilter {
|
|||||||
private final RedisTokenService redisTokenService;
|
private final RedisTokenService redisTokenService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException {
|
||||||
|
|
||||||
final String authorizationHeader = request.getHeader("Authorization");
|
logRequestDetails(request);
|
||||||
|
|
||||||
|
try {
|
||||||
|
String jwt = extractJwtFromRequest(request);
|
||||||
|
if (jwt == null) {
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String username = extractUsernameFromToken(jwt);
|
||||||
|
if (username == null) {
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTokenBlacklisted(jwt, response)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isUserNotAuthenticated(username)) {
|
||||||
|
authenticateUser(jwt, username);
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.warn("Error occurred during JWT filter processing", ex);
|
||||||
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private String extractJwtFromRequest(HttpServletRequest request) {
|
||||||
|
|
||||||
String jwt = null;
|
String jwt = null;
|
||||||
String username = null;
|
|
||||||
|
|
||||||
|
// 1. 先从 Authorization Header 中提取
|
||||||
|
String authorizationHeader = request.getHeader("Authorization");
|
||||||
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
|
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
|
||||||
jwt = authorizationHeader.substring(7);
|
jwt = authorizationHeader.substring(7);
|
||||||
try {
|
}
|
||||||
username = JwtUtils.extractUsername(jwt);
|
|
||||||
} catch (Exception e) {
|
// 2. 如果 Header 中没有,则尝试从 URL 参数中获取(如 X-Token)
|
||||||
logger.warn("Failed to extract username from token");
|
if (jwt == null || jwt.isEmpty()) {
|
||||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token");
|
jwt = request.getParameter("X-Token");
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
return jwt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractUsernameFromToken(String jwt) {
|
||||||
|
try {
|
||||||
|
return JwtUtils.extractUsername(jwt);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("Failed to extract username from token", e);
|
||||||
|
throw new RuntimeException("Failed to extract username from token");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTokenBlacklisted(String jwt, HttpServletResponse response) throws IOException {
|
||||||
|
if (redisTokenService.isBlacklisted(jwt)) {
|
||||||
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token is blacklisted");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUserNotAuthenticated(String username) {
|
||||||
|
return SecurityContextHolder.getContext().getAuthentication() == null ||
|
||||||
|
!SecurityContextHolder.getContext().getAuthentication().isAuthenticated() ||
|
||||||
|
!SecurityContextHolder.getContext().getAuthentication().getName().equals(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void authenticateUser(String jwt, String username) {
|
||||||
|
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||||
|
|
||||||
|
if (JwtUtils.validateToken(jwt, userDetails.getUsername())) {
|
||||||
|
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
|
||||||
|
userDetails, null, userDetails.getAuthorities());
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
} else {
|
} else {
|
||||||
// 没有 token,继续链(可能是登录接口等不需要认证的路径)
|
throw new RuntimeException("Token is expired or invalid");
|
||||||
chain.doFilter(request, response);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
|
||||||
if (redisTokenService.isBlacklisted(jwt)) {
|
|
||||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token is blacklisted");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
|
||||||
|
|
||||||
if (JwtUtils.validateToken(jwt, userDetails.getUsername())) {
|
/**
|
||||||
UsernamePasswordAuthenticationToken authentication =
|
* 封装的打印请求详情方法
|
||||||
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
|
*/
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
private void logRequestDetails(HttpServletRequest request) {
|
||||||
} else {
|
String requestURL = request.getRequestURL().toString();
|
||||||
// token 无效或已过期
|
String queryString = request.getQueryString();
|
||||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token is expired or invalid");
|
|
||||||
return;
|
// 打印基本信息
|
||||||
|
if (log.isInfoEnabled()) {
|
||||||
|
log.info("Request URL: {}", requestURL);
|
||||||
|
if (queryString != null) {
|
||||||
|
log.info("Query Parameters: {}", queryString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chain.doFilter(request, response);
|
// 打印参数(GET/POST 通用)
|
||||||
|
Enumeration<String> paramNames = request.getParameterNames();
|
||||||
|
while (paramNames.hasMoreElements()) {
|
||||||
|
String paramName = paramNames.nextElement();
|
||||||
|
String[] paramValues = request.getParameterValues(paramName);
|
||||||
|
for (String value : paramValues) {
|
||||||
|
log.debug("Request Param: {} = {}", paramName, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ public class UserDetailsServiceStore {
|
|||||||
@Bean
|
@Bean
|
||||||
public UserDetailsService users(PasswordEncoder passwordEncoder) {
|
public UserDetailsService users(PasswordEncoder passwordEncoder) {
|
||||||
UserDetails user = User.withUsername("admin")
|
UserDetails user = User.withUsername("admin")
|
||||||
.password(passwordEncoder.encode("password"))
|
.password(passwordEncoder.encode("123456"))
|
||||||
.roles("admin", "normal")
|
.roles("admin", "normal")
|
||||||
.authorities("app", "web")
|
.authorities("app", "web")
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ logging:
|
|||||||
root: INFO
|
root: INFO
|
||||||
com.arrokoth: DEBUG
|
com.arrokoth: DEBUG
|
||||||
org.springdoc: INFO
|
org.springdoc: INFO
|
||||||
org.springframework: INFO
|
org.springframework: DEBUG
|
||||||
|
|
||||||
#mybatis:
|
#mybatis:
|
||||||
# type-aliases-package: com.arrokoth.**.domain
|
# type-aliases-package: com.arrokoth.**.domain
|
||||||
|
|||||||
@@ -257,7 +257,7 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password-input">密码</label>
|
<label for="password-input">密码</label>
|
||||||
<input id="password-input" name="password" placeholder="请输入密码" type="password"
|
<input id="password-input" name="password" placeholder="请输入密码" type="password"
|
||||||
value="password">
|
value="123456">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" style="display: none">
|
<div class="form-group" style="display: none">
|
||||||
<label for="pass-captcha-input">验证码</label>
|
<label for="pass-captcha-input">验证码</label>
|
||||||
|
|||||||
Reference in New Issue
Block a user