创建工程spring-boot-security-oauth2
启动类
com.mirson.spring.boot.security.oauth.startup.SecurityOauthApplication
@SpringBootApplication
@ComponentScan(basePackages = {"com.mirson"})
@EnableCaching
public class SecurityOauthApplication {public static void main(String[] args) {SpringApplication.run(SecurityOauthApplication.class, args);}}
指定扫描路径, 开启缓存注解。
MAVEN依赖
POM.XML
<dependencies><!-- Spring Boot Security 安全依赖组件 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- Spring Boot Oauth2 认证组件 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId><version>2.1.1.RELEASE</version></dependency><!-- Spring Boot Web 依赖组件 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot 自动化缓存依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><!--Spring Boot Data Redis 缓存依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- Apache Commons 工具依赖 --><dependency><groupId>org.apachemons</groupId><artifactId>commons-lang3</artifactId></dependency></dependencies>
这里的依赖采用spring-cloud的OAUTH2封装来实现的自动化配置, 与spring-boot-starter-oauth2依赖实质是一样, 都是基于Spring-Security封装, 属性配置基本一致, 如果要加入Spring Cloud, 可以直接集成使用。
定义两个用户对象, 一个是OAUTH的用户认证对象, 一个是我们接口测试的用户对象。
OAUTH用户认证对象
com.mirson.spring.boot.security.oauth.po.OAuthUser
@Data
public class OAuthUser extends User {/*** 用户ID标识*/private Integer id;/*** 创建日期*/private Date createTime;public OAuthUser(String account, String password){super(account, password, true, true, true, true, Collections.EMPTY_SET);this.id = Int(0, 100);ateTime = new Date();}}
接口测试用户对象
com.mirson.spring.boot.security.oauth.po.User
@Data
public class User {/*** ID*/private Integer id;/*** 用户名称*/private String name;/*** 年龄*/private String age;/*** 省份*/private String province;/*** 创建时间*/private Date createDate;}
定义一个获取用户信息的接口, 受资源权限保护。
com.mirson.spring.boot.ller.UserController
@RestController
@RequestMapping("/user")
@Log4j2
public class UserController {@RequestMapping("/getUserInfo")@ResponseBodypublic User getUserInfo() {User user = new User();user.setId(0);user.setAge("21");user.setName("user1");user.setCreateDate(new Date());return user;}}
工程配置
# 服务端口
server:port: 22619
# 服务名称
spring:application:name: security-oauth2
这里我们便于测试, 我们将认证服务和资源服务放置一起,以上配置即可, 不需加任何其他配置。
如果资源服务是独立的, 工程配置需要加入以下信息:
## spring security 配置
security:oauth2:resource:jwt:# JWT 密钥信息key-value: sign_secret# TOKEN验证接口地址 token-info-uri: 127.0.0.1:21619/oauth/check_tokenclient:# 客户端模式配置client-id: democlient-secret: 123456scope: serveraccess-token-uri: 127.0.0.1:21619/oauth/tokenuser-authorization-uri: 127.0.0.1:21619/oauth/authorize
认证服务配置
新建com.mirson.spring.boot.fig.AuthorizationServerConfig配置类, 加入以下配置:
Redis 配置
/*** Redis 缓存配置
* @return*/@Beanpublic RedisTemplate<String, Object> stockRedisTemplate() {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());redisTemplate.setConnectionFactory(redisConnectionFactory);return redisTemplate;}
设置redis的key, value 序列化方式。
采用Redis存储TOKEN信息
/*** TokenStore实现方式, 采用Redis缓存* @return*/@Beanpublic TokenStore redisTokenStore() {RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);tokenStore.setPrefix(OAUTH_PREFIX_KEY);tokenStore.setAuthenticationKeyGenerator(new DefaultAuthenticationKeyGenerator() {@Overridepublic String extractKey(OAuth2Authentication authentication) {actKey(authentication);}});return tokenStore;}
统一Redis的Key前缀, 便于维护。
结合Token增强技术
/*** token增强处理, 支持扩展信息* @return TokenEnhancer*/@Beanpublic TokenEnhancer tokenEnhancer() {return (accessToken, authentication) -> {try {if (OAUTH_CLIENT_CREDENTIALS.OAuth2Request().getGrantType())) {return accessToken;}final Map<String, Object> additionalInfo = new HashMap<>(16);OAuthUser authUser = (OAuthUser) UserAuthentication().getPrincipal();if (null != authUser) {// 放入扩展信息additionalInfo.put("oauth_user_id", Id());additionalInfo.put("oauth_user_date", CreateTime());additionalInfo.put("active", true);}((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);}catch(Exception e) {(e.getMessage(), e);}return accessToken;};}
TOKEN增强可以放置额外信息,扩展性强, 更为灵活, 这些信息不会加入JWT中。
JWT TOKEN配置
/*** JWT TOKEN配置,采用签名密钥*/@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(OAUTH_SIGN_KEY);return converter;}
JWT可以支持密钥签名, 还可以通过证书签名方式, 安全性比较高。
采用内存模式对客户端进行验证
@Overridepublic void configure(ClientDetailsServiceConfigurer clients)throws Exception {clients.inMemory().withClient("demo").secret("4QrcOUm6Wau+VuBX8g+IPg==").authorizedGrantTypes("password", "authorization_code");}
原始密码为123456, 我们采用了密码编码器, 这里的密码要设置为密文。
认证服务配置
/*** 认证服务配置* @param endpoints*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) {// 自定义token生成方式TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST).tokenStore(redisTokenStore()).tokenEnhancer(tokenEnhancerChain).userDetailsService(authCustomUserDetailService).authenticationManager(authenticationManager).reuseRefreshTokens(false);}
采用Token链, 申请TOKEN的时候, 不仅返回JWT信息, 还返回TOKEN 增强设置的信息。
自定义密码编码器
com.mirson.spring.boot.fig.AuthPasswordEncoder
/*** 自定义密码加密方式*/
@Component
@Log4j2
public class AuthPasswordEncoder implements PasswordEncoder {/*** 编码处理* @param rawPassword* @return*/@Overridepublic String encode(CharSequence rawPassword) {String();}/*** 密码校验判断* @param rawPassword* @param encodedPassword* @return*/@Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {if(rawPassword != null && rawPassword.length() > 0){try {// 这里通过MD5及B64加密String password = String());boolean isMatch= encodedPassword.equals(password);if(!isMatch) {log.warn(" password not match!");}return encodedPassword.equals(password);} catch (Exception e) {(e.getMessage(), e);}}return false;}}
可以自定义编码, 比如BASE64等, 自定义校验逻辑,能够灵活处理。
认证服务WEB配置
com.mirson.spring.boot.fig.WebSecurityConfiguration
/*** 认证相关配置*/
@Primary
@Order(90)
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService authCustomClientDetailService;@Autowiredprivate AuthPasswordEncoder authPasswordEncoder;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/user/getUserInfo").authenticated().anyRequest().permitAll().and().csrf().disable() // 禁用csrf保护(防止伪造攻击).httpBasic().disable(); // 禁用弹出式认证框}@Bean@Override@SneakyThrowspublic AuthenticationManager authenticationManagerBean() {return super.authenticationManagerBean();}@Autowired@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(authCustomClientDetailService).passwordEncoder(authPasswordEncoder);}}
主要看configure方法配置, 设置哪些需要鉴权的接口地址, 禁用csrf保护, 防止无法请求的情况, 禁用弹出式认证框, 防止调用资源接口时出现401错误。
自定义用户服务接口
com.mirson.spring.boot.fig.AuthCustomUserDetailService
@Service("authCustomUserDetailService")
public class AuthCustomUserDetailService implements UserDetailsService {@Autowiredprivate CacheManager cacheManager;@Overridepublic UserDetails loadUserByUsername(String userNo) throws UsernameNotFoundException {// 查询缓存Cache cache = Cache(AuthorizationServerConfig.OAUTH_KEY_USER_DETAILS);if (cache != null && (userNo) != null) {return (UserDetails) (userNo).get();}// 封装成OAUTH鉴权的用户对象UserDetails userDetails = new OAuthUser("admin", "AZICOnu9cyUFFvBp3xi1AA==");// 将用户信息放入缓存cache.put(userNo, userDetails);return userDetails;}
}
这里加入了缓存处理, 实际项目当中, 也推荐使用缓存, 提升处理性能。
如果缓存没有用户, 会构造一个新的用户放入缓存, 密码要采用密文。
资源服务配置
如果有提供受保护的资源服务, 必须要做具体的配置。
新建com.mirson.spring.boot.fig.ResourceServerConfiguration
/*** 自定义资源服务器配置*/
@EnableResourceServer
@Configuration
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.antMatcher("/user/getUserInfo").authorizeRequests().anyRequest().authenticated();}
}
设置了一个受保护的资源接口/user/getUserInfo, 其他接口全部放行。
申请TOKEN,获取JWT与TOKEN增强信息
这里填入的是客户端模式的用户名和密码,并非认证用户信息。
设置密码模式的请求参数信息
请求返回结果
可以看到JWT的TOKEN信息, 以及增强设置中的ID和DATE信息。
访问受保护的资源接口
请求获取用户信息接口, 如果不传入TOKEN, 会提示无权访问
传入TOKEN访问
能够正常访问接口, 注意, 传入的TOKEN要选择【Bearer Token】方式。
访问TOKEN信息
请求接口, 传入token参数: 127.0.0.1:22619/oauth/check_token
可以看到JWT TOKEN的详细信息。
源码下载地址:
本文发布于:2024-01-29 05:20:38,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170647684412983.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |