当前位置: 首页 > 知识库问答 >
问题:

Thymeleaf附加安全不适用于Spring安全

颛孙智勇
2023-03-14

因此,作为一个初学者,我曾尝试使用spring boot 2.2.11、spring security、thymeleaf和json web令牌创建一个ecommmerce网站,我的问题是,当用户对模板进行身份验证时,即使我在模板中放置了thymeleaf的isAnonyms和IsAuthentificated标记,模板也没有更改。

我有两个问题:

1-/如何告诉所有控制器用户已经登录?

2-/如何将jwt令牌从后端传递到前端,以便用户可以提出特定请求?

这是我的pom。xml:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.11.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.webjars/bootstrap -->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator</artifactId>
            <version>0.30</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>

        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version></version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>demo</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

我索引的一部分。包含thymeleaf标记的html:



                <div class="forms ml-auto">
                    <a th:href="@{/login}" class="btn" sec:authorize="isAnonymous()"><span
                            class="fa fa-user-circle-o"></span> Sign In</a>
                    <a th:href="@{/signup}" class="btn" sec:authorize="isAnonymous()"><span
                            class="fa fa-pencil-square-o"></span> Sign Up</a>
                    <a th:href="@{/account}" class="btn" sec:authorize="isAuthenticated()"><span
                            class="fa fa-pencil-square-o"></span> Account</a>
                    <a th:href="@{/cart}" class="btn"> Cart <span> 0 </span> <i class="fa fa-shopping-cart"></i> </a>
                    <a th:href="@{/logout}" class="btn" sec:authorize="isAuthenticated()"><span
                            class="fa fa-user-circle-o"></span> Logout</a>

                </div>

我的登录控制器:


 @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login(Model model) {
        model.addAttribute("userDto",new UserDto());
        return "signin";
    }
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(@ModelAttribute("userDto") @Valid UserDto userDto, BindingResult result , RedirectAttributes ra){
        authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userDto.getEmail(),userDto.getPassword()));
        final UserDetails userDetails = userDetailsService.loadUserByUsername(userDto.getEmail());
        if (!userDetails.getUsername().equalsIgnoreCase(userDto.getEmail()) ){

            result.rejectValue("email",null,"Wrong Email");
        }

        if (!bCryptPasswordEncoder.matches(userDto.getPassword(),userDetails.getPassword())){
            result.rejectValue("password","null","Wrong Password");
        }
        if (result.hasErrors()){
            ra.addFlashAttribute("userDto",userDto);
            return "signin";
        }
        final String jwt = jwtUtil.generateToken(userDetails);
        System.out.println(jwt);
        return "index";

    }

我的Spring Security配置:


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/resources/**", "/static/**", "/public/**").permitAll()
                .antMatchers("/", "/signin/", "/signup","/**").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/user/**")
                .hasAnyRole("USER", "ADMIN")

                .anyRequest().authenticated().and().sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and().formLogin().loginPage("/signin").defaultSuccessUrl("/")
                    .usernameParameter("email").passwordParameter("password")
                    .permitAll()
                    .defaultSuccessUrl("/",true)
                .and().logout().logoutSuccessUrl("/")
                .logoutRequestMatcher(new AntPathRequestMatcher("/home/logout"));


        http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);


    }

登录前:

img_登录前

登录后的图像:

重定向到索引

成功登录并切换到其他页面:

切换页面

ps:如果有任何解决方案或建议,我将不胜感激。

共有1个答案

裴理
2023-03-14

您可以通过在控制器中指定主体作为方法参数来获取用户是否已通过身份验证。如果值为null,则请求未经过身份验证。否则,将对请求进行身份验证。

@GetMapping("/foo")
String foo(Principal principal) {
    boolean isAuthenticated = principal != null;
    ...
}

通常,当身份验证成功时,您会提供JWT。这是一个示例应用程序。

第一步是提供一种对用户进行身份验证的方法。在本例中,我们使用基本身份验证验证用户名/密码。

@Configuration
public class RestConfig extends WebSecurityConfigurerAdapter {

    @Value("${jwt.public.key}")
    RSAPublicKey key;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.authorizeRequests((authz) -> authz.anyRequest().authenticated())
            .csrf((csrf) -> csrf.ignoringAntMatchers("/token"))
            .httpBasic(Customizer.withDefaults())
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
            .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .exceptionHandling((exceptions) -> exceptions
                .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
                .accessDeniedHandler(new BearerTokenAccessDeniedHandler())
            );
        // @formatter:on
    }

    @Bean
    UserDetailsService users() {
        // @formatter:off
        return new InMemoryUserDetailsManager(
            User.withUsername("user")
                .password("{noop}password")
                .authorities("app")
                .build()
        );
        // @formatter:on
    }

    @Bean
    JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withPublicKey(this.key).build();
    }

}

然后,在基本身份验证成功后,它到达控制器,该控制器在响应中生成成功的JWT:

@RestController
public class TokenController {

    @Value("${jwt.private.key}")
    RSAPrivateKey key;

    @PostMapping("/token")
    public String token(Authentication authentication) {
        Instant now = Instant.now();
        long expiry = 36000L;
        // @formatter:off
        String scope = authentication.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.joining(" "));
        JWTClaimsSet claims = new JWTClaimsSet.Builder()
                .issuer("self")
                .issueTime(new Date(now.toEpochMilli()))
                .expirationTime(new Date(now.plusSeconds(expiry).toEpochMilli()))
                .subject(authentication.getName())
                .claim("scope", scope)
                .build();
        // @formatter:on
        JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256).build();
        SignedJWT jwt = new SignedJWT(header, claims);
        return sign(jwt).serialize();
    }

    SignedJWT sign(SignedJWT jwt) {
        try {
            jwt.sign(new RSASSASigner(this.key));
            return jwt;
        }
        catch (Exception ex) {
            throw new IllegalArgumentException(ex);
        }
    }

}

注意:您没有明确询问,但Thymeleaf标记似乎不起作用的可能原因是您处于无状态应用程序中,因此登录后身份验证会立即丢失,因为没有创建会话。

 类似资料:
  • 我正在尝试设置Firebase规则,如果$uid等于auth,则该规则将授予对R/W的访问权限。uid。我用firebase phone auth登录。 我正在尝试这条规则: 这条规则: 我尝试访问数据时出错(权限被拒绝)。 我遵循Firebase的说明,此规则通过模拟器。 当这些规则到位时,我不会从Firebase获得带有快照的实例。 如果你能帮助解决这个问题,我将不胜感激。 我正在尝试授予读取

  • 我试着给多个URL全部许可,但我得到了403。当我禁用csrf时,所有请求都在没有身份验证的情况下工作。请在下面找到我的安全配置。 请指正我遗漏的地方。谢谢你...

  • 我试图让我的web应用程序重新使用新的Spring Boot版本1.3.5工作,但是thymeleaf方言似乎不再工作了。 我补充说 (尽管我认为spring boot会为我做到这一点)。温使用了像E。g. 表达式将不会呈现,因为角色似乎是空的,尽管我可以将自定义用户元素注入控制器: 从调试中,我看到注入的主体对象不是null,但模板似乎无法解析sec:objects。我删除了xmlns命名空间并

  • 我安装了docker工具箱,我正在尝试连接到我的私有注册表。 我将以下内容添加到 我可以成功登录注册表。但是当我尝试从注册表拉/推到注册表时,我收到以下错误。 任何帮助都将不胜感激。谢谢

  • 我们正在使用Spring Security和角色、特权以及Spring ACL。前端由Thymeleaf(版本3)渲染。应用程序用户既可以具有不同权限的角色,也可以直接访问ACL设置的某些域对象。 具体示例 我有一个表,显示由ACL保护域对象。有一些行动,我想限制由SEC:授权检查,是否允许当前的用户执行这个行动。 但是,由于某种原因,hasPermission评估在这里不起作用。我无法访问本地s

  • 问题内容: 我正在运行一个基于Java Spring MVC的Web应用程序。它还基于Hybris平台。 现在,已经实现了有关身份验证和授权的基本功能。意味着我们确实有用于会话,有效的用户系统等的过滤器。 但是,我们目前还没有针对诸如XSS和其他可能的攻击之类的安全措施。XSS可能是最大的问题,因为它是最常见的攻击方式。 现在,我不知道……明智地采取什么步骤?我环顾四周,我发现存在像XSS-Fil