This commit is contained in:
haoxr 2020-11-17 20:23:21 +08:00
parent c4b2dee1d7
commit c616af407f
9 changed files with 102 additions and 129 deletions

View File

@ -70,7 +70,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
// refresh token有两种使用方式重复使用(true)非重复使用(false)默认为true
// 1 重复使用access token过期刷新时 refresh token过期时间未改变仍以初次生成的时间为准
// 2 非重复使用access token过期刷新时 refresh token过期时间延续在refresh token有效期内刷新便永不失效达到无需再次登录的目的
.reuseRefreshTokens(true);
.reuseRefreshTokens(false);
}
/**

View File

@ -1,39 +1,107 @@
package com.youlai.auth.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.*;
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.AuthenticationException;
import org.springframework.security.core.CredentialsContainer;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@Configuration
@EnableWebSecurity
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
.and()
.authorizeRequests().antMatchers("/oauth/public_key","/oauth/logout").permitAll().anyRequest().authenticated()
.and()
.csrf().disable();
// 登录失败处理handler返回一段json
http
.formLogin().failureHandler(
(req, resp, e) -> {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status", 401);
if (e instanceof LockedException) {
map.put("msg", "账户被锁定,登录失败!");
} else if (e instanceof BadCredentialsException) {
map.put("msg", "用户名或密码输入错误,登录失败!");
} else if (e instanceof DisabledException) {
map.put("msg", "账户被禁用,登录失败!");
} else if (e instanceof AccountExpiredException) {
map.put("msg", "账户过期,登录失败!");
} else if (e instanceof CredentialsContainer) {
map.put("msg", "密码过期,登录失败");
} else {
map.put("msg", "登录失败!");
}
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
)
.and()
.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
.and()
.authorizeRequests().antMatchers("/oauth/public_key", "/oauth/logout").permitAll().anyRequest().authenticated()
.and()
.csrf().disable();
}
/**
* 如果不配置SpringBoot会自动配置一个AuthenticationManager,覆盖掉内存中的用户
* 如果不配置SpringBoot会自动配置一个AuthenticationManager,覆盖掉内存中的用户
*/
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
AuthenticationFailureHandler authenticationFailureHandler() {
return (request, response, e) -> {
/*
if (!user.isEnabled()) {
throw new DisabledException("该账户已被禁用!");
} else if (!user.isAccountNonLocked()) {
throw new LockedException("该账号已被锁定!");
} else if (!user.isAccountNonExpired()) {
throw new AccountExpiredException("该账号已过期!");
} else if (!user.isCredentialsNonExpired()) {
throw new CredentialsExpiredException("该账户的登录凭证已过期,请重新登录!");
}
*/
if (e instanceof DisabledException) {
log.info(e.getMessage());
} else if (e instanceof LockedException) {
log.info(e.getMessage());
} else if (e instanceof AccountExpiredException) {
log.info(e.getMessage());
}
};
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}

View File

@ -0,0 +1,18 @@
package com.youlai.auth.exception;
import com.youlai.common.core.result.Result;
import com.youlai.common.core.result.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
@Slf4j
public class AuthExceptionHandler {
@ExceptionHandler(InvalidTokenException.class)
public Result handleBizException(InvalidTokenException e) {
return Result.custom(ResultCode.TOKEN_INVALID_OR_EXPIRED);
}
}

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>youlai-common</artifactId>
<groupId>com.youlai</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-database</artifactId>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,32 +0,0 @@
package com.youlai.common.database.config;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.youlai.common.database.handler.MetaHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
public class MybatisPlusConfig {
/**
* 分页插件自动识别数据库类型 多租户请参考官网插件扩展
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
/**
* 自动填充数据库创建人创建时间更新人更新时间
*/
@Bean
public GlobalConfig globalConfig() {
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setMetaObjectHandler(new MetaHandler());
return globalConfig;
}
}

View File

@ -1,25 +0,0 @@
package com.youlai.common.database.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @author haoxr
**/
@Component
public class MetaHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("gmtCreate", new Date(), metaObject);
this.setFieldValByName("gmtModified", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("gmtCreate", new Date(), metaObject);
}
}

View File

@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.youlai.common.database.config.MybatisPlusConfig

View File

@ -22,10 +22,10 @@
<version>${youlai.version}</version>
</dependency>
<!-- spring boot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

View File

@ -1,6 +1,5 @@
package com.youlai.gateway.config;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
import com.youlai.common.core.constant.AuthConstants;
@ -21,7 +20,6 @@ import org.springframework.security.config.annotation.web.reactive.EnableWebFlux
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
@ -48,15 +46,14 @@ public class ResourceServerConfig {
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http.oauth2ResourceServer().jwt()
.jwtAuthenticationConverter(jwtAuthenticationConverter());
http.oauth2ResourceServer().authenticationEntryPoint(serverAuthenticationEntryPoint());
//http.formLogin().authenticationFailureHandler(serverAuthenticationFailureHandler());
http.oauth2ResourceServer().authenticationEntryPoint(authenticationEntryPoint());
http.authorizeExchange()
.pathMatchers(ArrayUtil.toArray(whiteListConfig.getUrls(), String.class)).permitAll()
.anyExchange().access(authorizationManager)
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler()) // 处理未授权
.authenticationEntryPoint(serverAuthenticationEntryPoint()) //处理未认证
.authenticationEntryPoint(authenticationEntryPoint()) //处理未认证
.and().csrf().disable();
return http.build();
@ -87,37 +84,17 @@ public class ResourceServerConfig {
};
}
/**
* token无效或者已过期
*
* @return
*/
@Bean
ServerAuthenticationEntryPoint serverAuthenticationEntryPoint() {
ServerAuthenticationEntryPoint authenticationEntryPoint() {
return (exchange, e) -> {
Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getResponse()))
.flatMap(response -> {
response.setStatusCode(HttpStatus.OK);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin", "*");
response.getHeaders().set("Cache-Control", "no-cache");
String body = JSONUtil.toJsonStr(Result.custom(ResultCode.TOKEN_INVALID_OR_EXPIRED));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
return response.writeWith(Mono.just(buffer))
.doOnError(error -> DataBufferUtils.release(buffer));
});
return mono;
};
}
@Bean
ServerAuthenticationFailureHandler serverAuthenticationFailureHandler() {
return (exchange, e) -> {
Mono<Void> mono = Mono.defer(() -> Mono.just(exchange.getExchange().getResponse()))
.flatMap(response -> {
response.setStatusCode(HttpStatus.OK);
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin", "*");
response.getHeaders().set("Cache-Control", "no-cache");
@ -131,6 +108,7 @@ public class ResourceServerConfig {
}
/**
* @return
* @link https://blog.csdn.net/qq_24230139/article/details/105091273
@ -148,6 +126,4 @@ public class ResourceServerConfig {
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
}
}