我的用户使用Amazon Cognito使用this plugin登录我的应用程序.

我还有一个Spring Boot应用程序用户界面,也是由Cogito保护的.

在我的应用程序流程中的某个时刻,我想要显示Spring Boot应用程序的Web视图,以让用户配置其他内容.

如何在不让用户再次登录的情况下执行此操作?

如果我创建了一个名为/LOGIN/{用户名}/{Password}的终结点,并使用SecurityConextHolder让用户登录并重定向到/home,这是否是一种糟糕的做法?

推荐答案

我终于把它修好了.

首先,我登录了,并使用调试器使代码在某处停止,这样我就可以查找SecurityContextHolder.getContext().getAuthentication().我的身份验证对象的类型为OAuth2AuthenticationToken.我仔细看了一下,决定复制它. 我在一个定制的身份验证管理器中完成了这项工作,并在覆盖的身份验证方法中返回了我的OAuth2AuthenticationToken.

CustomAuthenticationManager.java

@Component
public class CustomAuthenticationManager implements AuthenticationManager {

    @Bean
    protected PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String token = ((Jwt)authentication.getPrincipal()).getTokenValue();
        if (token == null)
            throw new BadCredentialsException("Invalid token");
        return convertAccessToken(token);
    }

    public OAuth2AuthenticationToken convertAccessToken(String accessToken){
        Jwt decode = Tools.parseToken(accessToken);

        List<GrantedAuthority> authorities = new ArrayList<>();
        for (String s : ((String[]) decode.getClaims().get("cognito:groups"))) {
            authorities.add(new SimpleGrantedAuthority("ROLE_" + s));
        }
        Map<String, Object> claims = decode.getClaims();
        OidcIdToken oidcIdToken = new OidcIdToken(decode.getTokenValue(), decode.getIssuedAt(), decode.getExpiresAt(), claims);
        DefaultOidcUser user = new DefaultOidcUser(authorities, oidcIdToken, "email");
        return new OAuth2AuthenticationToken(user, authorities, "cognito");
    }

}

另外,我还将其放在静态工具中.

    public static Jwt parseToken(String accessToken) {
        DecodedJWT decode = com.auth0.jwt.JWT.decode(accessToken);
        HashMap<String, Object> headers = new HashMap<>();
        headers.put("alg", decode.getHeaderClaim("alg").asString());
        headers.put("kid", decode.getHeaderClaim("kid").asString());

        HashMap<String, Object> claims = new HashMap<>();
        decode.getClaims().forEach((k, v) -> {
            switch(k){
                case "cognito:roles":
                case "cognito:groups":
                    claims.put(k, v.asArray(String.class));
                    break;
                case "auth_time":
                case "exp":
                case "iat":
                    claims.put(k, v.asLong());
                    break;
                default:
                    claims.put(k, v.asString());
                    break;
            }
        });

        return new Jwt(accessToken, decode.getIssuedAt().toInstant(), decode.getExpiresAt().toInstant(), headers,  claims);
    }

然后,我创建了两个端点.一个是我的"登录页面",一个是我的过滤器转到的页面.因此,在我的登录页面中,我接受了一个访问令牌,将其存储在会话中,然后重定向到通过筛选器的另一个端点.

TokenLoginController.java

@Component
@RestController
public class TokenLoginController {

    @GetMapping(value="/login/token/{token}")
    @PermitAll
    public void setSession(@PathVariable("token") String token, HttpSession session, HttpServletResponse response) throws IOException {
        session.setAttribute("access_token", token);
        response.sendRedirect("/login/token");
    }

    @GetMapping(value="/login/token")
    @PermitAll
    public void setSession() {

    }

}

该筛选器扩展AbstractAuthenticationProcessingFilter,从会话中查找访问令牌,创建OAuth2AuthenticationToken,并使用它进行身份验证.

StickyAuthenticationFilter.java

public class StickyAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public StickyAuthenticationFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) {
        super(defaultFilterProcessesUrl);
        setAuthenticationManager(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws AuthenticationException, IOException, ServletException {

        String access_token = (String)servletRequest.getSession().getAttribute("access_token");
        if (access_token != null) {
            JwtAuthenticationToken authRequest = new JwtAuthenticationToken(Tools.parseToken(access_token));
            return getAuthenticationManager().authenticate(authRequest);
        }

        throw new RuntimeException("Invalid access token");
    }

}

最后,我的SecurityConfig将这一切联系在一起,如下所示:

@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends VaadinWebSecurity {

    private final ClientRegistrationRepository clientRegistrationRepository;

    public SecurityConfig(ClientRegistrationRepository clientRegistrationRepository) {
        this.clientRegistrationRepository = clientRegistrationRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests().antMatchers("/login/token/*", "/login/token").permitAll().and()
                .addFilterBefore(new StickyAuthenticationFilter("/login/token", new CustomAuthenticationManager()), BearerTokenAuthenticationFilter.class)
                .oauth2ResourceServer(oauth2 -> oauth2.jwt())
                .authorizeRequests()
                .antMatchers("/user/**")
                .authenticated();
        super.configure(http);
        setOAuth2LoginPage(http, "/oauth2/authorization/cognito");
        http.oauth2Login(l -> l.userInfoEndpoint().userAuthoritiesMapper(userAuthoritiesMapper()));
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // Customize your WebSecurity configuration.
        super.configure(web);
    }

    @Bean
    public GrantedAuthoritiesMapper userAuthoritiesMapper() {
        return (authorities) -> {
            Set<GrantedAuthority> mappedAuthorities = new HashSet<>();

            Optional<OidcUserAuthority> awsAuthority = (Optional<OidcUserAuthority>) authorities.stream()
                    .filter(grantedAuthority -> "ROLE_USER".equals(grantedAuthority.getAuthority()))
                    .findFirst();

            if (awsAuthority.isPresent()) {
                if (awsAuthority.get().getAttributes().get("cognito:groups") != null) {
                    mappedAuthorities = ((JSONArray) awsAuthority.get().getAttributes().get("cognito:groups")).stream()
                            .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                            .collect(Collectors.toSet());
                }
            }

            return mappedAuthorities;
        };
    }
}

Flutter相关问答推荐

如何在不使用NULL-check(!)的情况下缩小`FutureBuilder.Builder()`内部的`Snaphot`范围

CLI数据库连接后将SHA-1密钥添加到Firebase项目

audioQuery不会等待判断存储权限

BoxConstraints强制使用无限宽度(列中的Listview)

框中的Flutter 适配图像

在Flutter 小部件测试中找不到框中的AssetImage装饰

按一下按钮即可更新 fl_chart

请求已在 flutter 中发送到 django 服务器,并且已返回响应,但条件仍然为 false

Riverpod Provider.family 和 HookConsumerWidget 不刷新 UI

为什么我的图标的一半在定位小部件中消失了?

Flutter记录返回类型问题

Flutter中pubspec.yaml文件中的name参数是什么?

Flutter:使用 GlobalKey 访问 BlocProvider

Flutter ImagePicker - 在 onPressed 中异步获取图像显示 lint 警告

如何从 Flutter 中的 App2 远程点击 App1 中的按钮

如何将 chrome web 模拟器添加到 vs code

有没有办法为文本中的下划线创建自定义样式?

我无法从 Cloud firestore 访问文档字段并在 statefulwidget 类中显示它

Firebase 中的查询限制 - .orderBy() 错误

Flutter RawMaterialButton 常量相对大小