Demo:第三章:权限框架 spring security oauth2
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public B8AuthTokenEnhancer b8AuthTokenEnhancer() {
return new B8AuthTokenEnhancer();
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(){
JwtAccessTokenConverter accessTokenConverter = new
JwtAccessTokenConverter();
//配置 JWT 使用的秘钥 非对称加密
accessTokenConverter.setKeyPair(keyPair());
return accessTokenConverter;
}
@Autowired
private JwtCAProperties jwtCAProperties;
@Bean
public KeyPair keyPair() {
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource(jwtCAProperties.getKeyPairName()), jwtCAProperties.getKeyPairSecret().toCharArray());
return keyStoreKeyFactory.getKeyPair(jwtCAProperties.getKeyPairAlias(), jwtCAProperties.getKeyPairStoreSecret().toCharArray());
}
}
RedisConfig
package com.b8.auth.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
/**
@author zhiwei Liao
*/
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public TokenStore tokenStore(){
// access_token
return new RedisTokenStore(redisConnectionFactory);
}
}
WebSecurityConfig
package com.b8.auth.config;
import com.b8.auth.service.B8AuthUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
@Description 配置 SpringSecurity,“将 Spring Security 与 Spring Gateway 一起使用时出现无法访问 javax.servlet.Filter”错误”,
把 Spring Gateway 和 Spring Security 放在一起,因为我想保护我的网关。但是在实现了以下扩展 WebSecurityConfigurerAdapter 的类之后,
项目抛出 java:无法访问 javax.servlet.Filter
从 Spring Cloud Gateway 文档中:Spring Cloud Gateway 需要 Spring Boot 和 Spring Webflux 提供的 Netty 运行时。
它不能在传统的 Servlet 容器中工作,也不能在构建为 WAR 时工作。扩展 WebSecurityConfigurerAdapter 是为了基于 servlet 的应用程序
@Author zhiwei Liao
@Date 2021/8/17 15:44
**/
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private B8AuthUserDetailService userDetailService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
@Description 密码模式
@MethodReturnType org.springframework.security.crypto.password.PasswordEncoder
@Author zhiwei Liao
@Date 2021/8/17 15:46
**/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().permitAll()
.and().authorizeRequests()
.antMa 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 tchers("/oauth/**").permitAll()//不拦截
.anyRequest()
.authenticated()
.and().logout().permitAll()//退出放行
.and().csrf().disable();
}
}
UserinfoDetails
package com.b8.auth.domain;
import com.common.entity.po.B8UserUserinfoEntity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Arrays;
import java.util.Collection;
/**
@author zhiwei Liao
*/
public class UserinfoDetails implements UserDetails {
private B8UserUserinfoEntity userUserinfo;
public UserinfoDetails(B8UserUserinfoEntity userUserinfo) {
this.userUserinfo = userUserinfo;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
//返回当前用户的权限 BRAC user role authority
return Arrays.asList(new SimpleGrantedAuthority("TEST"));
}
// 获取用户密码(凭证)
@Override
public String getPassword() {
return userUserinfo.getCredential();
}
// 获取用户名
@Override
public String getUsername() {
return userUserinfo.getNickNameId();
}
// 判断帐号是否已经过期
@Override
public boolean isAccountNonExpired() {
return true;
}
// 判断帐号是否已被锁定
@Override
public boolean isAccountNonLocked() {
return true;
}
// 判断用户凭证是否已经过期
@Override
public boolean isCredentialsNonExpired() {
return true;
}
// 判断用户帐号是否已启用
@Override
public boolean isEnabled() {
return !userUserinfo.getUserStatus().equals("FREEZE");
}
public B8UserUserinfoEntity getUserUserinfo() {
return userUserinfo;
}
}
B8AuthTokenEnhancer
package com.b8.auth.enhancer;
import com.b8.auth.domain.UserinfoDetails;
import com.common.entity.po.B8UserUserinfoEntity;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import java.util.HashMap;
import java.util.Map;
public class B8AuthTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
UserinfoDetails userinfoDetails = (UserinfoDetails) authentication.getPrincipal();
final Map<String, Object> additionalInfo = new HashMap<>();
final Map<String, Object> retMap = new HashMap<>();
//todo 这里暴露 userId 到 Jwt 的令牌中,后期可以根据自己的业务需要 进行添加字段
additionalInfo.put("userId",userinfoDetails.getUserUserinfo().getId());
additionalInfo.put("userName",userinfoDetails.getUserUserinfo().getNickNameId());
additionalInfo.put("nickName",userinfoDetails.getUserUserinfo().getDisplayName());
additionalInfo.put("loginType",userinfoDetails.getUserUserinfo().getLoginType());
retMap.put("additionalInfo",additionalInfo);
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(retMap);
return accessToken;
}
}
JwtCAProperties
package com.b8.auth.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
@Description 读取配置文件中的属性配置
@Author zhiwei Liao
@Date 2021/8/18 10:04
**/
@Data
@ConfigurationProperties(prefix = "b8auth.jwt")
public class JwtCAProperties {
/**
证书名称
*/
private String keyPairName;
/**
证书别名
*/
private String keyPairAlias;
/**
证书私钥
*/
private String keyPairSecret;
/**
证书存储密钥
*/
private String keyPairStoreSecret;
}
UserServiceHystrix
package com.b8.auth.service.impl;
import com.b8.auth.api.ResultData;
import com.b8.auth.service.UserInfoFeignService;
import com.common.entity.po.B8UserUserinfoEntity;
import org.springframework.stereotype.Component;
/**
@author zhiwei Liao
@version 1.0
@Description
@Date 2021/8/17 15:25
*/
@Component
public class UserServiceHystrix implements UserInfoFeignService {
@Override
public ResultData<B8UserUserinfoEntity> getUserinfoById(String userId) {
return null;
}
@Override
public ResultData<B8UserUserinfoEntity> getUserByUsername(String username) {
return null;
}
}
B8AuthUserDetailService
package com.b8.auth.service;
import com.b8.auth.api.ResultData;
import com.b8.auth.domain.UserinfoDetails;
import com.common.entity.po.B8UserUserinfoEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
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 zhiwei Liao
@version 1.0
@Description
@Date 2021/8/17 15:02
*/
@Service
@Slf4j
public class B8AuthUserDetailService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// TODO 查数据库获取用户信息 rpc 调用
// 加载用户信息
if (StringUtils.isEmpty(username)) {
log.warn("用户登陆用户名为空:{}", username);
throw new UsernameNotFoundException("用户名不能为空");
}
B8UserUserinfoEntity userUserinfo = getByUsername(username);
if (null == userUserinfo) {
log.warn("根据用户名没有查询到对应的用户信息:{}", username);
}
log.info("根据用户名:{}获取用户登陆信息:{}", username, userUserinfo);
// 用户信息的封装 implements UserDetails
UserinfoDetails memberDetails = new UserinfoDetails(userUserinfo);
return memberDetails;
}
@Autowired
private UserInfoFeignService userInfoFeignService;
public B8UserUserinfoEntity getByUsername(String username) {
// fegin 获取用户信息
ResultData<B8UserUserinfoEntity> resultData = userInfoFeignService.getUserByUsername(username);
return resultData.getData();
}
}
UserInfoFeignService
package com.b8.auth.service;
import com.b8.auth.api.ResultData;
import com.b8.auth.service.impl.UserServiceHystrix;
import com.common.entity.po.B8UserUserinfoEntity;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
@author zhiwei Liao
@version 1.0
@Description
@Date 2021/8/17 15:24
*/
@Component
@FeignClient(name = "user", fallback = UserServiceHystrix.class, path = "/user")
public interface UserInfoFeignService {
@GetMapping("/getUserinfoById")
ResultData<B8UserUserinfoEntity> getUserinfoById(@RequestParam("userId") String userId);
@GetMapping("/getUserByUsername")
ResultData<B8UserUserinfoEntity> getUserByUsername(@RequestParam("username") String username);
}
IErrorCode
package com.b8.auth.api;
/**
封装 API 的错误码
*/
public interface IErrorCode {
int getCode();
String getMessage();
}
ResultCode
package com.b8.auth.api;
/**
枚举了一些常用 API 操作码
*/
public enum ResultCode implements IErrorCode {
SUCCESS(200, "操作成功"),
FAILED(500, "操作失败"),
VALIDATE_FAILED(404, "参数检验失败"),
UNAUTHORIZED(401, "暂未登录或 token 已经过期"),
AUTHORIZATION_HEADER_IS_EMPTY(600,"请求头中的 token 为空"),
GET_TOKEN_KEY_ERROR(601,"远程获取 TokenKey 异常"),
GEN_PUBLIC_KEY_ERROR(602,"生成公钥异常"),
JWT_TOKEN_EXPIRE(603,"token 校验异常"),
TOMANY_REQUEST_ERROR(429,"后端服务触发流控"),
BACKGROUD_DEGRADE_ERROR(604,"后端服务触发降级"),
BAD_GATEWAY(502,"网关服务异常"),
FORBIDDEN(403, "没有相关权限");
private int code;
private String message;
private ResultCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
ResultData
package com.b8.auth.api;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
public class ResultData<T> implements Serializable {
/**
状态码
*/
public boolean status = true;
/**
状态码
*/
private Integer code = 200;
/**
接口返回信息
*/
private String msg;
/**
数据对象
*/
private T data;
/**
初始化一个新创建的 ResultData 对象
@param status 状态码
@param msg 返回内容
*/
public ResultData(Boolean status, String msg) {
this.status = status;
this.msg = msg;
}
/**
初始化一个新创建的 ResultData 对象
@param status 状态码
@param msg 返回内容
@param data 数据对象
*/
public ResultData(Boolean status, String msg, T data, Integer code) {
this.status = status;
this.msg = msg;
this.data = data;
this.code = code;
}
public ResultData(T data) {
this.data = data;
}
/**
返回成功消息
@param msg 返回内容
@param data 数据对象
@return 成功消息
*/
public static <T> ResultData<T> success(String msg, T data) {
return new ResultData<T>(true, msg, data, 200);
}
/**
返回成功消息
@param msg 返回内容
@return 成功消息
*/
public static <T> ResultData<T> success(String msg) {
return ResultData.success(msg, null);
}
/**
返回成功消息
@return 成功消息
*/
public static <T> ResultData<T> success() {
return ResultData.success(null);
}
/**
返回成功数据
@return 成功消息
*/
public static <T> ResultData<T> success(T data) {
return ResultData.success(null, data);
}
/**
返回错误消息
@return
*/
public static <T> ResultData<T> error() {
return ResultData.error(null);
}
/**
返回错误消息
@param msg 返回内容
@return 警告消息
*/
public static <T> ResultData<T> error(String msg) {
return ResultData.error(msg, null);
}
评论