committed by
Gitee
19 changed files with 408 additions and 251 deletions
@ -0,0 +1,36 @@ |
|||
package com.bx.implatform.config; |
|||
|
|||
import com.bx.implatform.interceptor.AuthInterceptor; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
|||
import org.springframework.security.crypto.password.PasswordEncoder; |
|||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
|||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
|||
|
|||
|
|||
@Configuration |
|||
public class MvcConfig implements WebMvcConfigurer { |
|||
|
|||
|
|||
@Override |
|||
public void addInterceptors(InterceptorRegistry registry) { |
|||
registry.addInterceptor(authInterceptor()) |
|||
.addPathPatterns("/**") |
|||
.excludePathPatterns( "/image/upload","/login","/logout","/register","/refreshToken", |
|||
"/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**"); |
|||
} |
|||
|
|||
|
|||
@Bean |
|||
public AuthInterceptor authInterceptor() { |
|||
return new AuthInterceptor(); |
|||
} |
|||
|
|||
@Bean |
|||
public PasswordEncoder passwordEncoder(){ |
|||
// 使用BCrypt加密密码
|
|||
return new BCryptPasswordEncoder(); |
|||
} |
|||
|
|||
} |
|||
@ -1,172 +0,0 @@ |
|||
package com.bx.implatform.config; |
|||
|
|||
import com.alibaba.fastjson.JSON; |
|||
import com.bx.implatform.enums.ResultCode; |
|||
import com.bx.implatform.result.Result; |
|||
import com.bx.implatform.result.ResultUtils; |
|||
import com.bx.implatform.service.IUserService; |
|||
import com.bx.implatform.session.UserSession; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Qualifier; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.security.authentication.*; |
|||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; |
|||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; |
|||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
|||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; |
|||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; |
|||
import org.springframework.security.core.userdetails.User; |
|||
import org.springframework.security.core.userdetails.UserDetailsService; |
|||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
|||
import org.springframework.security.crypto.password.PasswordEncoder; |
|||
import org.springframework.security.web.AuthenticationEntryPoint; |
|||
import org.springframework.security.web.authentication.AuthenticationFailureHandler; |
|||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; |
|||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; |
|||
|
|||
import java.io.PrintWriter; |
|||
|
|||
/* |
|||
* SpringSecurity安全框架配置 |
|||
* |
|||
* @Author Blue |
|||
* @Date 2022/10/21 |
|||
*/ |
|||
@Slf4j |
|||
@Configuration |
|||
@EnableWebSecurity |
|||
@EnableGlobalMethodSecurity(prePostEnabled=true) |
|||
public class WebSecurityConfg extends WebSecurityConfigurerAdapter { |
|||
|
|||
|
|||
|
|||
@Qualifier("securityUserDetailsServiceImpl") |
|||
@Autowired |
|||
private UserDetailsService userDetailsService; |
|||
|
|||
@Autowired |
|||
private IUserService userService; |
|||
|
|||
@Override |
|||
protected void configure(HttpSecurity http) throws Exception { |
|||
http.authorizeRequests() |
|||
.antMatchers("/image/upload","/login","/logout","/register","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**") |
|||
.permitAll() |
|||
.anyRequest() //任何其它请求
|
|||
.authenticated() //都需要身份认证
|
|||
.and() |
|||
// 登录配置表单认证方式
|
|||
.formLogin() |
|||
.usernameParameter("username")//设置登录账号参数,与表单参数一致
|
|||
.passwordParameter("password")//设置登录密码参数,与表单参数一致
|
|||
.loginProcessingUrl("/login")//配置默认登录入口
|
|||
.successHandler(successHandler()) |
|||
.failureHandler(failureHandler()) |
|||
.and() |
|||
// 注销
|
|||
.logout() |
|||
.logoutUrl("/logout") |
|||
.logoutSuccessHandler(logoutHandler()) |
|||
.permitAll() |
|||
.and() |
|||
// session管理
|
|||
.sessionManagement() |
|||
.and() |
|||
// 禁用跨站csrf攻击防御
|
|||
.csrf() |
|||
.disable() |
|||
.exceptionHandling() |
|||
.authenticationEntryPoint(entryPoint()); |
|||
|
|||
} |
|||
|
|||
@Bean |
|||
AuthenticationFailureHandler failureHandler(){ |
|||
return (request, response, exception) -> { |
|||
response.setContentType("application/json;charset=utf-8"); |
|||
PrintWriter out = response.getWriter(); |
|||
Result result = ResultUtils.error(ResultCode.LOGIN_ERROR,exception.getMessage()); |
|||
if (exception instanceof LockedException) { |
|||
result =ResultUtils.error(ResultCode.LOGIN_ERROR,"账户被锁定,请联系管理员!"); |
|||
} else if (exception instanceof CredentialsExpiredException) { |
|||
result = ResultUtils.error(ResultCode.LOGIN_ERROR,"密码过期,请联系管理员!"); |
|||
} else if (exception instanceof AccountExpiredException) { |
|||
result =ResultUtils.error(ResultCode.LOGIN_ERROR,"账户过期,请联系管理员!"); |
|||
} else if (exception instanceof DisabledException) { |
|||
result = ResultUtils.error(ResultCode.LOGIN_ERROR,"账户被禁用,请联系管理员!"); |
|||
} else if (exception instanceof BadCredentialsException) { |
|||
result =ResultUtils.error(ResultCode.LOGIN_ERROR,"用户名或者密码输入错误,请重新输入!"); |
|||
} |
|||
out.write(new ObjectMapper().writeValueAsString(result)); |
|||
out.flush(); |
|||
out.close(); |
|||
}; |
|||
} |
|||
|
|||
@Bean |
|||
AuthenticationSuccessHandler successHandler(){ |
|||
return (request, response, authentication) -> { |
|||
User useDetail = (User)authentication.getPrincipal(); |
|||
String strJson = useDetail.getUsername(); |
|||
UserSession userSession = JSON.parseObject(strJson,UserSession.class); |
|||
log.info("用户 '{}' 登录,id:{},昵称:{}",userSession.getUserName(),userSession.getId(),userSession.getNickName()); |
|||
// 响应
|
|||
response.setContentType("application/json;charset=utf-8"); |
|||
PrintWriter out = response.getWriter(); |
|||
Result result = ResultUtils.success(); |
|||
out.write(new ObjectMapper().writeValueAsString(result)); |
|||
out.flush(); |
|||
out.close(); |
|||
|
|||
}; |
|||
} |
|||
|
|||
|
|||
@Bean |
|||
LogoutSuccessHandler logoutHandler(){ |
|||
return (request, response, authentication) -> { |
|||
User useDetail = (User)authentication.getPrincipal(); |
|||
String strJson = useDetail.getUsername(); |
|||
UserSession userSession = JSON.parseObject(strJson,UserSession.class); |
|||
log.info("用户 '{}' 退出,id:{},昵称:{}",userSession.getUserName(),userSession.getId(),userSession.getNickName()); |
|||
// 响应
|
|||
response.setContentType("application/json;charset=utf-8"); |
|||
PrintWriter out = response.getWriter(); |
|||
Result result = ResultUtils.success(); |
|||
out.write(new ObjectMapper().writeValueAsString(result)); |
|||
out.flush(); |
|||
out.close(); |
|||
}; |
|||
} |
|||
|
|||
@Bean |
|||
AuthenticationEntryPoint entryPoint(){ |
|||
return (request, response, exception) -> { |
|||
response.setContentType("application/json;charset=utf-8"); |
|||
PrintWriter out = response.getWriter(); |
|||
Result result = ResultUtils.error(ResultCode.NO_LOGIN); |
|||
out.write(new ObjectMapper().writeValueAsString(result)); |
|||
out.flush(); |
|||
out.close(); |
|||
}; |
|||
} |
|||
|
|||
|
|||
|
|||
@Bean |
|||
public PasswordEncoder passwordEncoder(){ |
|||
// 使用BCrypt加密密码
|
|||
return new BCryptPasswordEncoder(); |
|||
} |
|||
|
|||
|
|||
@Override |
|||
protected void configure(AuthenticationManagerBuilder auth) throws Exception { |
|||
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
package com.bx.implatform.controller; |
|||
|
|||
|
|||
import com.bx.implatform.result.Result; |
|||
import com.bx.implatform.result.ResultUtils; |
|||
import com.bx.implatform.service.IUserService; |
|||
import com.bx.implatform.dto.LoginDTO; |
|||
import com.bx.implatform.dto.RegisterDTO; |
|||
import com.bx.implatform.vo.LoginVO; |
|||
import io.swagger.annotations.Api; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import javax.validation.Valid; |
|||
|
|||
|
|||
|
|||
@Api(tags = "用户登录和注册") |
|||
@RestController |
|||
public class LoginController { |
|||
|
|||
@Autowired |
|||
private IUserService userService; |
|||
|
|||
@PostMapping("/login") |
|||
@ApiOperation(value = "用户注册",notes="用户注册") |
|||
public Result register(@Valid @RequestBody LoginDTO dto){ |
|||
LoginVO vo = userService.login(dto); |
|||
return ResultUtils.success(vo); |
|||
} |
|||
|
|||
|
|||
@PutMapping("/refreshToken") |
|||
@ApiOperation(value = "刷新token",notes="用refreshtoken换取新的token") |
|||
public Result refreshToken(@RequestHeader("refreshToken")String refreshToken){ |
|||
LoginVO vo = userService.refreshToken(refreshToken); |
|||
return ResultUtils.success(vo); |
|||
} |
|||
|
|||
|
|||
@PostMapping("/register") |
|||
@ApiOperation(value = "用户注册",notes="用户注册") |
|||
public Result register(@Valid @RequestBody RegisterDTO dto){ |
|||
userService.register(dto); |
|||
return ResultUtils.success(); |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
package com.bx.implatform.controller; |
|||
|
|||
|
|||
import com.bx.implatform.result.Result; |
|||
import com.bx.implatform.result.ResultUtils; |
|||
import com.bx.implatform.service.IUserService; |
|||
import com.bx.implatform.vo.RegisterVO; |
|||
import io.swagger.annotations.Api; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import javax.validation.Valid; |
|||
|
|||
|
|||
|
|||
@Api(tags = "用户注册") |
|||
@RestController |
|||
public class RegisterController { |
|||
|
|||
@Autowired |
|||
private IUserService userService; |
|||
|
|||
@PostMapping("/register") |
|||
@ApiOperation(value = "用户注册",notes="用户注册") |
|||
public Result register(@Valid @RequestBody RegisterVO dto){ |
|||
userService.register(dto); |
|||
return ResultUtils.success(); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
package com.bx.implatform.dto; |
|||
|
|||
import io.swagger.annotations.ApiModel; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Data; |
|||
import org.hibernate.validator.constraints.Length; |
|||
|
|||
import javax.validation.constraints.NotEmpty; |
|||
|
|||
@Data |
|||
@ApiModel("用户登录VO") |
|||
public class LoginDTO { |
|||
|
|||
//@NotEmpty(message="用户名不可为空")
|
|||
@ApiModelProperty(value = "用户名") |
|||
private String userName; |
|||
|
|||
// @NotEmpty(message="用户密码不可为空")
|
|||
@ApiModelProperty(value = "用户密码") |
|||
private String password; |
|||
|
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
package com.bx.implatform.interceptor; |
|||
|
|||
|
|||
import com.alibaba.fastjson.JSON; |
|||
import com.auth0.jwt.exceptions.JWTVerificationException; |
|||
import com.bx.implatform.contant.Constant; |
|||
import com.bx.implatform.enums.ResultCode; |
|||
import com.bx.implatform.exception.GlobalException; |
|||
import com.bx.implatform.session.UserSession; |
|||
import com.bx.implatform.util.JwtUtil; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.method.HandlerMethod; |
|||
import org.springframework.web.servlet.HandlerInterceptor; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
; |
|||
|
|||
@Slf4j |
|||
public class AuthInterceptor implements HandlerInterceptor { |
|||
|
|||
|
|||
@Override |
|||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
|||
//如果不是映射到方法直接通过
|
|||
if (!(handler instanceof HandlerMethod)) { |
|||
return true; |
|||
} |
|||
//从 http 请求头中取出 token
|
|||
String token = request.getHeader("accessToken"); |
|||
if (token == null) { |
|||
log.error("未登陆,url:{}",request.getRequestURI()); |
|||
throw new GlobalException(ResultCode.NO_LOGIN); |
|||
} |
|||
try{ |
|||
//验证 token
|
|||
JwtUtil.checkSign(token, Constant.ACCESS_TOKEN_SECRET); |
|||
}catch ( |
|||
JWTVerificationException e) { |
|||
log.error("token已失效,url:{}",request.getRequestURI()); |
|||
throw new GlobalException(ResultCode.INVALID_TOKEN); |
|||
} |
|||
// 存放session
|
|||
String strJson = JwtUtil.getInfo(token); |
|||
UserSession userSession = JSON.parseObject(strJson,UserSession.class); |
|||
request.setAttribute("session",userSession); |
|||
return true; |
|||
} |
|||
} |
|||
@ -0,0 +1,80 @@ |
|||
package com.bx.implatform.util; |
|||
|
|||
import com.auth0.jwt.JWT; |
|||
import com.auth0.jwt.JWTVerifier; |
|||
import com.auth0.jwt.algorithms.Algorithm; |
|||
import com.auth0.jwt.exceptions.JWTDecodeException; |
|||
import java.util.Date; |
|||
|
|||
|
|||
public class JwtUtil { |
|||
|
|||
/** |
|||
* 生成jwt字符串,30分钟后过期 JWT(json web token) |
|||
* @param userId |
|||
* @param info |
|||
* @param expireIn |
|||
* @param secret |
|||
* @return |
|||
* */ |
|||
public static String sign(Long userId, String info,long expireIn,String secret) { |
|||
try { |
|||
Date date = new Date(System.currentTimeMillis() + expireIn*1000); |
|||
Algorithm algorithm = Algorithm.HMAC256(secret); |
|||
return JWT.create() |
|||
//将userId保存到token里面
|
|||
.withAudience(userId.toString()) |
|||
//存放自定义数据
|
|||
.withClaim("info", info) |
|||
//五分钟后token过期
|
|||
.withExpiresAt(date) |
|||
//token的密钥
|
|||
.sign(algorithm); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 根据token获取userId |
|||
* @param token |
|||
* @return |
|||
* */ |
|||
public static Long getUserId(String token) { |
|||
try { |
|||
String userId = JWT.decode(token).getAudience().get(0); |
|||
return Long.parseLong(userId); |
|||
}catch (JWTDecodeException e) { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 根据token获取自定义数据info |
|||
* @param token |
|||
* @return |
|||
* */ |
|||
public static String getInfo(String token) { |
|||
try { |
|||
return JWT.decode(token).getClaim("info").asString(); |
|||
}catch (JWTDecodeException e) { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 校验token |
|||
* @param token |
|||
* @param secret |
|||
* @return |
|||
* */ |
|||
public static boolean checkSign(String token,String secret) { |
|||
Algorithm algorithm = Algorithm.HMAC256(secret); |
|||
JWTVerifier verifier = JWT.require(algorithm) |
|||
//.withClaim("username, username)
|
|||
.build(); |
|||
verifier.verify(token); |
|||
return true; |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
package com.bx.implatform.vo; |
|||
|
|||
import io.swagger.annotations.ApiModel; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
@ApiModel("用户登录VO") |
|||
public class LoginVO { |
|||
|
|||
@ApiModelProperty(value = "每次请求都必须在header中携带accessToken") |
|||
private String accessToken; |
|||
|
|||
@ApiModelProperty(value = "accessToken过期时间(秒)") |
|||
private Integer accessTokenExpiresIn; |
|||
|
|||
@ApiModelProperty(value = "accessToken过期后,通过refreshToken换取新的token") |
|||
private String refreshToken; |
|||
|
|||
@ApiModelProperty(value = "refreshToken过期时间(秒)") |
|||
private Integer refreshTokenExpiresIn; |
|||
} |
|||
Loading…
Reference in new issue