feat(新增): 🚀 整合springSecurity
This commit is contained in:
parent
2621e03020
commit
cc6212a050
Binary file not shown.
|
@ -46,5 +46,22 @@
|
||||||
<artifactId>velocity-engine-core</artifactId>
|
<artifactId>velocity-engine-core</artifactId>
|
||||||
<version>2.0</version>
|
<version>2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- redis -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- redisson 分布式锁-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson</artifactId>
|
||||||
|
<version>3.11.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.data</groupId>
|
||||||
|
<artifactId>spring-data-redis</artifactId>
|
||||||
|
<version>3.2.4</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
package com.atguigu.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Slf4j
|
||||||
|
public class RedisConfiguration {
|
||||||
|
/**
|
||||||
|
* 使用StringRedisSerializer序列化为字符串
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
|
||||||
|
log.info("RedisConfiguration===>使用StringRedisSerializer序列化为字符串");
|
||||||
|
|
||||||
|
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||||
|
redisTemplate.setConnectionFactory(connectionFactory);
|
||||||
|
// 设置key序列化为string
|
||||||
|
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||||
|
// 设置value序列化为JSON,使用GenericJackson2JsonRedisSerializer替换默认序列化
|
||||||
|
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
|
||||||
|
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||||
|
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
|
||||||
|
|
||||||
|
return redisTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解决cache(@Cacheable)把数据缓存到redis中的value是乱码问题
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public CacheManager cacheManager(RedisConnectionFactory factory) {
|
||||||
|
log.info("RedisConfiguration===>解决cache(@Cacheable)把数据缓存到redis中的value是乱码问题");
|
||||||
|
|
||||||
|
// 配置序列化
|
||||||
|
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
|
||||||
|
config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
|
||||||
|
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer()))
|
||||||
|
.entryTtl(Duration.ofDays(365));
|
||||||
|
|
||||||
|
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
|
||||||
|
.cacheDefaults(config).build();
|
||||||
|
return cacheManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定的日期模式
|
||||||
|
*/
|
||||||
|
public Jackson2JsonRedisSerializer<Object> jsonRedisSerializer() {
|
||||||
|
log.info("RedisConfiguration===>指定的日期模式");
|
||||||
|
|
||||||
|
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
// 设置ObjectMapper访问权限
|
||||||
|
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||||
|
// 记录序列化之后的数据类型,方便反序列化
|
||||||
|
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
|
||||||
|
// LocalDatetime序列化,默认不兼容jdk8日期序列化
|
||||||
|
JavaTimeModule timeModule = new JavaTimeModule();
|
||||||
|
timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||||
|
timeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||||
|
|
||||||
|
timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
// 关闭默认的日期格式化方式,默认UTC日期格式 yyyy-MM-dd’T’HH:mm:ss.SSS
|
||||||
|
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||||
|
mapper.registerModule(timeModule);
|
||||||
|
|
||||||
|
serializer.setObjectMapper(mapper);
|
||||||
|
return serializer;
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,22 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
<scope>provided</scope>
|
</dependency>
|
||||||
|
<!-- redis -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- redisson 分布式锁-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson</artifactId>
|
||||||
|
<version>3.11.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.data</groupId>
|
||||||
|
<artifactId>spring-data-redis</artifactId>
|
||||||
|
<version>3.2.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
package com.atguigu.security.config;
|
||||||
|
|
||||||
|
import com.atguigu.security.custom.CustomMd5PasswordEncoder;
|
||||||
|
import com.atguigu.security.filter.TokenAuthenticationFilter;
|
||||||
|
import com.atguigu.security.filter.TokenLoginFilter;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
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.builders.WebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity //@EnableWebSecurity是开启SpringSecurity的默认行为
|
||||||
|
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||||
|
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
@Autowired
|
||||||
|
private UserDetailsService userDetailsService;
|
||||||
|
@Autowired
|
||||||
|
private CustomMd5PasswordEncoder customMd5PasswordEncoder;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Override
|
||||||
|
protected AuthenticationManager authenticationManager() throws Exception {
|
||||||
|
return super.authenticationManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
// 这是配置的关键,决定哪些接口开启防护,哪些接口绕过防护
|
||||||
|
http
|
||||||
|
// 关闭csrf跨站请求伪造
|
||||||
|
.csrf().disable()
|
||||||
|
// 开启跨域以便前端调用接口
|
||||||
|
.cors().and()
|
||||||
|
.authorizeRequests()
|
||||||
|
// 指定某些接口不需要通过验证即可访问。登陆接口肯定是不需要认证的
|
||||||
|
//.antMatchers("/admin/system/index/login").permitAll()
|
||||||
|
// 这里意思是其它所有接口需要认证才能访问
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
.and()
|
||||||
|
// TokenAuthenticationFilter放到UsernamePasswordAuthenticationFilter的前面,这样做就是为了除了登录的时候去查询数据库外,其他时候都用token进行认证。
|
||||||
|
.addFilterBefore(new TokenAuthenticationFilter(redisTemplate),
|
||||||
|
UsernamePasswordAuthenticationFilter.class)
|
||||||
|
.addFilter(new TokenLoginFilter(authenticationManager(), redisTemplate));
|
||||||
|
|
||||||
|
// 禁用session
|
||||||
|
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
// 指定UserDetailService和加密器
|
||||||
|
auth.userDetailsService(userDetailsService).passwordEncoder(customMd5PasswordEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置哪些请求不拦截
|
||||||
|
* 排除swagger相关请求
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void configure(WebSecurity web) throws Exception {
|
||||||
|
web.ignoring().antMatchers("/admin/modeler/**", "/diagram-viewer/**", "/editor-app/**", "/*.html",
|
||||||
|
"/admin/processImage/**",
|
||||||
|
"/admin/wechat/authorize", "/admin/wechat/userInfo", "/admin/wechat/bindPhone",
|
||||||
|
"/favicon.ico", "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/doc.html");
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,4 +13,4 @@ public class CustomMd5PasswordEncoder implements PasswordEncoder {
|
||||||
public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
||||||
return encodedPassword.equals(DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes()));
|
return encodedPassword.equals(DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
package com.atguigu.security.custom;
|
package com.atguigu.security.custom;
|
||||||
|
|
||||||
import com.atguigu.model.system.SysUser;
|
import com.atguigu.model.system.SysUser;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.userdetails.User;
|
import org.springframework.security.core.userdetails.User;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
public class CustomUser extends User {
|
public class CustomUser extends User {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 我们自己的用户实体对象,要调取用户信息时直接获取这个实体对象。(这里我就不写get/set方法了)
|
* 我们自己的用户实体对象,要调取用户信息时直接获取这个实体对象。(这里我就不写get/set方法了)
|
||||||
*/
|
*/
|
||||||
|
@ -17,11 +22,4 @@ public class CustomUser extends User {
|
||||||
this.sysUser = sysUser;
|
this.sysUser = sysUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SysUser getSysUser() {
|
}
|
||||||
return sysUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSysUser(SysUser sysUser) {
|
|
||||||
this.sysUser = sysUser;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.atguigu.security.custom;
|
||||||
|
|
||||||
|
public class LoginUserInfoHelper {
|
||||||
|
|
||||||
|
private static final ThreadLocal<Long> userId = new ThreadLocal<Long>();
|
||||||
|
private static final ThreadLocal<String> username = new ThreadLocal<String>();
|
||||||
|
|
||||||
|
public static Long getUserId() {
|
||||||
|
return userId.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setUserId(Long _userId) {
|
||||||
|
userId.set(_userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeUserId() {
|
||||||
|
userId.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getUsername() {
|
||||||
|
return username.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setUsername(String _username) {
|
||||||
|
username.set(_username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeUsername() {
|
||||||
|
username.remove();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,10 +2,14 @@ package com.atguigu.security.custom;
|
||||||
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public interface UserDetailsService extends org.springframework.security.core.userdetails.UserDetailsService {
|
||||||
|
|
||||||
public interface UserDetailsService {
|
|
||||||
/**
|
/**
|
||||||
* 根据用户名获取用户对象(获取不到直接抛异常)
|
* 根据用户名获取用户对象(获取不到直接抛异常)
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
|
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
package com.atguigu.security.filter;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.atguigu.common.result.Result;
|
||||||
|
import com.atguigu.common.result.ResultCodeEnum;
|
||||||
|
import com.atguigu.common.utlis.JwtHelper;
|
||||||
|
import com.atguigu.common.utlis.ResponseUtil;
|
||||||
|
import com.atguigu.security.custom.LoginUserInfoHelper;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
public TokenAuthenticationFilter(RedisTemplate<String, Object> redisTemplate) {
|
||||||
|
this.redisTemplate = redisTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
FilterChain chain) throws ServletException, IOException {
|
||||||
|
// 如果是登录接口,直接放行
|
||||||
|
if ("/admin/system/index/login".equals(request.getRequestURI())) {
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
|
||||||
|
if (null != authentication) {
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
} else {
|
||||||
|
ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_MOBLE_ERROR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
|
||||||
|
// 请求头是否有token
|
||||||
|
String token = request.getHeader("token");
|
||||||
|
if (!StringUtils.isEmpty(token)) {
|
||||||
|
String username = JwtHelper.getUserName(token);
|
||||||
|
if (!StringUtils.isEmpty(username)) {
|
||||||
|
// 当前用户信息放到ThreadLocal里面
|
||||||
|
LoginUserInfoHelper.setUserId(JwtHelper.getUserId(token));
|
||||||
|
LoginUserInfoHelper.setUsername(username);
|
||||||
|
|
||||||
|
// 通过username从redis获取权限数据
|
||||||
|
String authString = (String) redisTemplate.opsForValue().get(username);
|
||||||
|
// 把redis获取字符串权限数据转换要求集合类型 List<SimpleGrantedAuthority>
|
||||||
|
if (!StringUtils.isEmpty(authString)) {
|
||||||
|
List<Map> maplist = JSON.parseArray(authString, Map.class);
|
||||||
|
System.out.println(maplist);
|
||||||
|
List<SimpleGrantedAuthority> authList = new ArrayList<>();
|
||||||
|
for (Map map : maplist) {
|
||||||
|
String authority = (String) map.get("authority");
|
||||||
|
authList.add(new SimpleGrantedAuthority(authority));
|
||||||
|
}
|
||||||
|
return new UsernamePasswordAuthenticationToken(username, null, authList);
|
||||||
|
} else {
|
||||||
|
return new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package com.atguigu.security.fillter;
|
package com.atguigu.security.filter;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.atguigu.common.result.Result;
|
import com.atguigu.common.result.Result;
|
||||||
import com.atguigu.common.result.ResultCodeEnum;
|
import com.atguigu.common.result.ResultCodeEnum;
|
||||||
import com.atguigu.common.utlis.JwtHelper;
|
import com.atguigu.common.utlis.JwtHelper;
|
||||||
|
@ -7,6 +8,7 @@ import com.atguigu.common.utlis.ResponseUtil;
|
||||||
import com.atguigu.security.custom.CustomUser;
|
import com.atguigu.security.custom.CustomUser;
|
||||||
import com.atguigu.vo.system.LoginVo;
|
import com.atguigu.vo.system.LoginVo;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
@ -15,67 +17,68 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
|
||||||
* <p>
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
* 登录过滤器,继承UsernamePasswordAuthenticationFilter,对用户名密码进行登录校验
|
|
||||||
* </p>
|
// 构造方法
|
||||||
*/
|
public TokenLoginFilter(AuthenticationManager authenticationManager,
|
||||||
public class TokenAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
|
RedisTemplate<String, Object> redisTemplate) {
|
||||||
public TokenAuthenticationFilter(AuthenticationManager authenticationManager) {
|
|
||||||
this.setAuthenticationManager(authenticationManager);
|
this.setAuthenticationManager(authenticationManager);
|
||||||
this.setPostOnly(false);
|
this.setPostOnly(false);
|
||||||
// 指定登录接口及提交方式,可以指定任意路径
|
// 指定登录接口及提交方式,可以指定任意路径
|
||||||
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login", "POST"));
|
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login", "POST"));
|
||||||
|
this.redisTemplate = redisTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 登录认证
|
||||||
* 登录认证
|
// 获取输入的用户名和密码,调用方法认证
|
||||||
*/
|
public Authentication attemptAuthentication(HttpServletRequest request,
|
||||||
@Override
|
HttpServletResponse response)
|
||||||
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
|
|
||||||
throws AuthenticationException {
|
throws AuthenticationException {
|
||||||
try {
|
try {
|
||||||
LoginVo loginVo = new ObjectMapper().readValue(req.getInputStream(), LoginVo.class);
|
// 获取用户信息
|
||||||
|
LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
|
||||||
Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
|
// 封装对象
|
||||||
|
Authentication authenticationToken =
|
||||||
|
new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
|
||||||
|
// 调用方法
|
||||||
return this.getAuthenticationManager().authenticate(authenticationToken);
|
return this.getAuthenticationManager().authenticate(authenticationToken);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 认证成功调用方法
|
||||||
* 登录成功
|
protected void successfulAuthentication(HttpServletRequest request,
|
||||||
*/
|
HttpServletResponse response,
|
||||||
@Override
|
FilterChain chain,
|
||||||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
|
Authentication auth) {
|
||||||
Authentication auth) throws IOException, ServletException {
|
// 获取当前用户
|
||||||
CustomUser customUser = (CustomUser) auth.getPrincipal();
|
CustomUser customUser = (CustomUser) auth.getPrincipal();
|
||||||
String token = JwtHelper.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername());
|
// 生成token
|
||||||
|
String token = JwtHelper.createToken(customUser.getSysUser().getId(),
|
||||||
|
customUser.getSysUser().getUsername());
|
||||||
|
|
||||||
|
// 获取当前用户权限数据,放到Redis里面 key:username value:权限数据
|
||||||
|
redisTemplate.opsForValue().set(customUser.getUsername(),
|
||||||
|
JSON.toJSONString(customUser.getAuthorities()));
|
||||||
|
|
||||||
|
// 返回
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
map.put("token", token);
|
map.put("token", token);
|
||||||
ResponseUtil.out(response, Result.success(map));
|
ResponseUtil.out(response, Result.success(map));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 认证失败调用方法
|
||||||
* 登录失败
|
protected void unsuccessfulAuthentication(HttpServletRequest request,
|
||||||
*/
|
HttpServletResponse response,
|
||||||
@Override
|
AuthenticationException failed) {
|
||||||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
ResponseUtil.out(response, Result.error(null, ResultCodeEnum.LOGIN_MOBLE_ERROR));
|
||||||
AuthenticationException e) {
|
|
||||||
if (e.getCause() instanceof RuntimeException) {
|
|
||||||
ResponseUtil.out(response, Result.error(null, 204, e.getMessage()));
|
|
||||||
} else {
|
|
||||||
ResponseUtil.out(response, Result.error(null, ResultCodeEnum.LOGIN_MOBLE_ERROR));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -405,3 +405,38 @@ Using generated security password: c1b9b421-40ec-420f-88cd-c249c5d26684
|
||||||
14:54:25:578 INFO 16348 --- [http-nio-8800-exec-4] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
|
14:54:25:578 INFO 16348 --- [http-nio-8800-exec-4] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
|
||||||
14:54:25:583 INFO 16348 --- [http-nio-8800-exec-4] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
|
14:54:25:583 INFO 16348 --- [http-nio-8800-exec-4] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
|
||||||
16:12:27:427 INFO 16348 --- [SpringContextShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
|
16:12:27:427 INFO 16348 --- [SpringContextShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
|
||||||
|
16:22:14:238 INFO 23040 --- [main] com.atguigu.auth.ServiceAuthApplication : Starting ServiceAuthApplication on Bunny with PID 23040 (F:\java项目\guigu-oa\guigu-oa\service-oa\target\classes started by ACE in F:\java项目\guigu-oa\guigu-oa)
|
||||||
|
16:22:14:239 INFO 23040 --- [main] com.atguigu.auth.ServiceAuthApplication : The following profiles are active: dev
|
||||||
|
16:22:14:830 INFO 23040 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
|
||||||
|
16:22:14:833 INFO 23040 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode.
|
||||||
|
16:22:14:855 INFO 23040 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 13ms. Found 0 Redis repository interfaces.
|
||||||
|
16:22:15:081 INFO 23040 --- [main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler@3c232051' of type [org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
|
||||||
|
16:22:15:085 INFO 23040 --- [main] trationDelegate$BeanPostProcessorChecker : Bean 'methodSecurityMetadataSource' of type [org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
|
||||||
|
16:22:15:412 INFO 23040 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8800 (http)
|
||||||
|
16:22:15:418 INFO 23040 --- [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||||
|
16:22:15:418 INFO 23040 --- [main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.39]
|
||||||
|
16:22:15:478 INFO 23040 --- [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||||
|
16:22:15:478 INFO 23040 --- [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1206 ms
|
||||||
|
16:22:15:587 INFO 23040 --- [main] com.atguigu.config.MybatisPlusConfig : 注入MybatisPlus配置类...
|
||||||
|
16:22:16:085 INFO 23040 --- [main] com.atguigu.config.RedisConfiguration : RedisConfiguration===>使用StringRedisSerializer序列化为字符串
|
||||||
|
16:22:16:347 INFO 23040 --- [main] com.atguigu.config.RedisConfiguration : RedisConfiguration===>解决cache(@Cacheable)把数据缓存到redis中的value是乱码问题
|
||||||
|
16:22:16:351 INFO 23040 --- [main] com.atguigu.config.RedisConfiguration : RedisConfiguration===>指定的日期模式
|
||||||
|
16:22:16:428 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/admin/modeler/**'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/diagram-viewer/**'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/editor-app/**'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/*.html'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/admin/processImage/**'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/admin/wechat/authorize'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/admin/wechat/userInfo'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/admin/wechat/bindPhone'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/favicon.ico'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/swagger-resources/**'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/webjars/**'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/v2/**'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/swagger-ui.html/**'], []
|
||||||
|
16:22:16:429 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/doc.html'], []
|
||||||
|
16:22:16:495 INFO 23040 --- [main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@39403943, org.springframework.security.web.context.SecurityContextPersistenceFilter@6e7f29d5, org.springframework.security.web.header.HeaderWriterFilter@ff8e36d, org.springframework.web.filter.CorsFilter@1c5fd813, org.springframework.security.web.authentication.logout.LogoutFilter@63ad5fe7, com.atguigu.security.filter.TokenAuthenticationFilter@49338f3, com.atguigu.security.filter.TokenLoginFilter@3c9971af, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@7f94541b, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@618fb1, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@4abdd5e, org.springframework.security.web.session.SessionManagementFilter@4f22fd5d, org.springframework.security.web.access.ExceptionTranslationFilter@94aeba1, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@7adbec34]
|
||||||
|
16:22:16:531 INFO 23040 --- [main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
|
||||||
|
16:22:16:712 INFO 23040 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8800 (http) with context path ''
|
||||||
|
16:22:16:982 INFO 23040 --- [main] com.atguigu.auth.ServiceAuthApplication : Started ServiceAuthApplication in 3.025 seconds (JVM running for 3.551)
|
||||||
|
16:22:35:146 INFO 23040 --- [SpringContextShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
|
||||||
|
|
Loading…
Reference in New Issue