java - 如何使用在层微服务中生成的令牌返回 HttpResponse
问题描述
向上!编辑:也许我的问题不够清楚:我的 API Web 控制器的控制器中的 HttpResponse 似乎不包含我在 MS-Authentication 中放入的 cookie 或 Jwt 令牌。我认为问题可能出在我在代理接口中声明的方法中。我需要什么样的回报才能更新我的回复?
我有一个微服务“身份验证”,一个带有 Zuul 的网关和一个 Api Web。
我使用 Spring Boot 安全性实现了 jwt 令牌安全性。
当我的用户尝试从 api web 登录时,用户名和密码被发送到 MS-Authentication(Zuul 配置为允许任何人调用此 MS),并且在验证用户在数据库中之后,它会生成一个令牌。
我的问题是我无法取回带有令牌的响应(或 cookie,我尝试将令牌放入 cookie 并添加 cookie 作为响应)。
这是我第一个使用 Spring Boot 和微服务的项目!
当我不使用 Api 并使用 postmann 进行测试时,令牌很好地返回响应!
这是我的代码:Api-web 中的 LoginController
@Controller
public class LoginController {
private final BookProxy bookProxy;
@Autowired
public LoginController(BookProxy bookProxy) {
this.bookProxy = bookProxy;
}
@GetMapping("/login")
public String loginForm(Model model){
model.addAttribute("user",new UserBean());
return "login";
}
@PostMapping("/login")
public String doLogin(@ModelAttribute UserBean user){
bookProxy.authenticateClient(user);
return "Home";
}
}
Api-web 中的代理
@FeignClient(name = "zuul-server", url = "localhost:8762")
public interface Proxy {
/* Login */
@PostMapping("/auth/login")
void authenticateClient(@RequestBody UserBean user);
}
Zuul 网关中的 SecurityConfig
@EnableWebSecurity
public class SecurityTokenConfig extends WebSecurityConfigurerAdapter {
// Roles
private static final String ADMIN = "ADMIN";
private static final String EMPLOYEE = "EMPLOYEE";
private static final String CLIENT = "CLIENT";
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterAfter(new JwtTokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.antMatchers("/book/**").hasAnyRole(ADMIN,EMPLOYEE)
.anyRequest().authenticated();
}
}
MS-Authentication 中的 SecurityConfig
@EnableWebSecurity
public class SecurityCredentialsConfig extends WebSecurityConfigurerAdapter {
private final UserPrincipalDetailsService userPrincipalDetailsService;
@Autowired
public SecurityCredentialsConfig(UserPrincipalDetailsService userPrincipalDetailsService) {
this.userPrincipalDetailsService = userPrincipalDetailsService;
}
// Roles
private static final String ADMIN = "ADMIN";
private static final String EMPLOYEE = "EMPLOYEE";
private static final String CLIENT = "CLIENT";
@Override
protected void configure(AuthenticationManagerBuilder auth){
auth
.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager()))
.authorizeRequests()
.antMatchers(HttpMethod.POST,"/auth/Login").permitAll()
.antMatchers("/book/consult/**").hasAnyRole(ADMIN,EMPLOYEE)
.antMatchers("/book/**").hasAnyRole(ADMIN,EMPLOYEE)
.anyRequest().authenticated();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(userPrincipalDetailsService);
return daoAuthenticationProvider;
}
}
过滤谁在 MS-Authentication 中对用户进行身份验证并生成令牌
public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private Logger log = LoggerFactory.getLogger(this.getClass());
// We use auth manager to validate the user credentials
private AuthenticationManager authManager;
JwtUsernameAndPasswordAuthenticationFilter(AuthenticationManager authManager) {
this.authManager = authManager;
// By default, UsernamePasswordAuthenticationFilter listens to "/login" path.
// I use "/auth" path so i need to override the defaults.
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(JwtConfig.URI, "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
// Grab credentials and map them to login viewmodel
LoginViewModel credentials = null;
try {
credentials = new ObjectMapper().readValue(request.getInputStream(), LoginViewModel.class);
} catch (IOException e) {
log.error(e.getMessage());
}
// Create login token
assert credentials != null;
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
credentials.getUsername(),
credentials.getPassword(),
new ArrayList<>());
// Return authenticate user
return authManager.authenticate(authenticationToken);
}
// Upon successful authentication, generate a token.
// The 'auth' passed to successfulAuthentication() is the current authenticated user.
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication auth) throws IOException, ServletException {
// Grab principal
UserPrincipal principal = (UserPrincipal) auth.getPrincipal();
String token = JWT.create()
//.withHeader(headerClaims)
.withClaim("role","ROLE_" + principal.getRole())
.withSubject(principal.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + JwtConfig.EXPIRATION))
.sign(HMAC512(JwtConfig.SECRET.getBytes()));
// ADD COOKIES
Cookie cookie = new Cookie(JwtConfig.HEADER, token);
cookie.setSecure(false);
cookie.setHttpOnly(true);
cookie.setMaxAge(999999);
cookie.setDomain("localhost");
cookie.setPath("/");
// Add token and cookie in response (try both)
response.addHeader(JwtConfig.HEADER, JwtConfig.PREFIX + token);
response.addCookie(cookie);
}
}
Jwt 配置常量
public class JwtConfig {
public static final String URI = "/auth/**";
public static final String HEADER = "Authorization";
public static final String PREFIX = "Bearer ";
public static final int EXPIRATION = 24*60*60;
public static final String SECRET = "JwtSecretKey";
}
解决方案
推荐阅读
- javascript - 在 webpack + react 中使用 sass-loader 出现多个错误
- java - Reactor 调度程序实施注意事项
- javascript - 将 HTML 对象添加到事件 javascript/meteor
- c# - 找不到方法 Microsoft.Owin.Security.Notifications.MessageReceivedNotification
- c++ - C++调用另一个子类的公共方法
- python - TesseractError: (-1073741819, u'') 使用 pytesseract 时
- git - 如何使用 --theirs 或 --ours 合并大多数冲突?
- .net - .net oracle 插入查询
- android - 如何使用 Delegates.Observable 获得新旧数据之间的差异?
- liquibase - Liquibase:如何为包/功能生成变更日志