首先引入jar包:
接下来是application.yml配置:
oAuth配置:
package com.vevor.mall.auth.config;
import com.vevor.mall.auth.constants.RedisConstant;
import com.vevor.mall.auth.entity.AuthUserDetails;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author lixinyu
* @date 2020-08-31
* @description 授权服务器配置
*/
@Configuration
@EnableAuthorizationServer
public class AuthenticationServerConfig extends AuthorizationServerConfigurerAdapter {
private final DataSource dataSource;
private final PasswordEncoder passwordEncoder;
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailsService;
private final LettuceConnectionFactory lettuceConnectionFactory;
public AuthenticationServerConfig(AuthenticationManager authenticationManager,
@Qualifier("userDetailsServiceImpl") UserDetailsService userDetailsService,
DataSource dataSource,
PasswordEncoder passwordEncoder,
LettuceConnectionFactory lettuceConnectionFactory) {
this.authenticationManager = authenticationManager;
this.dataSource = dataSource;
this.userDetailsService = userDetailsService;
this.passwordEncoder = passwordEncoder;
this.lettuceConnectionFactory=lettuceConnectionFactory;
}
/**
* 第三方客户端信息配置
* @param clients 定义客户端详细信息服务的配置程序
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
super.configure(clients);
// 客户端加密方式需要更换成加密模式
clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
// 此处可以修改默认的sql语句
JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
clients.withClientDetails(clientDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
.allowFormAuthenticationForClients()
.checkTokenAccess("permitAll()")
.passwordEncoder(passwordEncoder);
}
/**
* 定义授权Token
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
super.configure(endpoints);
/*
* 用于修改框架默认的访问路径
*/
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancer())
.userDetailsService(userDetailsService)
.reuseRefreshTokens(false)
// 对外开放的登录接口请求方式
.allowedTokenEndpointRequestMethods(HttpMethod.POST)
// 更改登录路径为自定义路径
.pathMapping("/oauth/token","/authLoginController/login")
.exceptionTranslator(new DefaultWebResponseExceptionTranslator());
}
/**
* 用户认证信息存放在Redis中,使用RedisStore进行存储
* @return tokenStore
*/
@Bean
public TokenStore tokenStore(){
RedisTokenStore tokenStore = new RedisTokenStore(lettuceConnectionFactory);
tokenStore.setPrefix(RedisConstant.REDIS_ACCOUNT_PREFIX);
return tokenStore;
}
@Bean
public TokenEnhancer tokenEnhancer(){
final Map<String,Object> additionalInfo = new HashMap<>(3);
return (oAuth2AccessToken, oAuth2Authentication) -> {
AuthUserDetails authUserDetails = (AuthUserDetails) oAuth2Authentication.getUserAuthentication().getPrincipal();
additionalInfo.put("userId", authUserDetails.getId());
additionalInfo.put("username", authUserDetails.getUsername());
// additionalInfo.put("mobile", authUserDetails.getMobile());
additionalInfo.put("authorities", authUserDetails.getAuthorities());
((DefaultOAuth2AccessToken) oAuth2AccessToken).setAdditionalInformation(additionalInfo);
return oAuth2AccessToken;
};
}
}
security配置:
package com.vevor.mall.auth.config;
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.AuthenticationManager;
import org.springframework.security.config.BeanIds;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
/**
* @author lixinyu
* @data 2020-08-31
*/
@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Service
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Qualifier("userDetailsServiceImpl")
@Autowired
private UserDetailsService userDetailsService;
/**
* http请求设置
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// 释放拦截的请求
.antMatchers("/authLoginController/**")
.permitAll()
.anyRequest().authenticated()
// 关闭打开的csrf保护
.and().csrf().disable()
// http基础认证
.httpBasic();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 配置用户密码加密方式,BCrypt实现加密器可以有效防止撞库
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 密码加密算法
* @return 加密算法,BCrypt实现加密器可以有效防止撞库
*/
@Bean
public PasswordEncoder passwordEncoder(){
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
}
实现UserDetailsService:
package com.vevor.mall.auth.config;
import com.vevor.mall.auth.entity.AuthUserDetails;
import com.vevor.mall.auth.service.IAuthUserService;
import com.vevor.mall.auth.vo.UserVO;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
* @author lixinyu
* @date 2020-08-31
* @description 权限框架查询用户详情服务实现类
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final IAuthUserService authUserService;
public UserDetailsServiceImpl(IAuthUserService authUserService) {
this.authUserService = authUserService;
}
/**
* 用户密码登录
* @param username 用户名
* @return UserDetails
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 根据用户名查询用户的接口
UserVO user = authUserService.queryUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户名不存在!");
}
return getUserDetails(user);
}
/**
* 构建用户信息
* @param userVO
* @return 用户详情
*/
private AuthUserDetails getUserDetails(UserVO userVO) {
// UserVO是用户实体类,AuthUserDetails是SpringSecurity认证用户详情对象
AuthUserDetails userDetails = new AuthUserDetails();
// 1. 用户详情封装(此处由于是继承关系,可以使用属性复制的方式)
BeanUtils.copyProperties(userVO, userDetails);
return userDetails;
}
}
完善查询接口,mapper,mybatis查询即可。
Redis缓存内容可通过工具查看。