GVKun编程网logo

Spring Security MultiHttpSecurity配置,这样我就可以执行两种身份验证。JWT令牌和会话Cookie

29

在本文中,我们将详细介绍SpringSecurityMultiHttpSecurity配置,这样我就可以执行两种身份验证。JWT令牌和会话Cookie的各个方面,同时,我们也将为您带来关于JavaSp

在本文中,我们将详细介绍Spring Security MultiHttpSecurity配置,这样我就可以执行两种身份验证。JWT令牌和会话Cookie的各个方面,同时,我们也将为您带来关于Java Spring Security配置-多个身份验证提供程序、Spring Boot HttpSecurity - @PreAuthorize - 如何设置 AuthenticationFilter? 使用 Spring Security 的内置 JWT 支持无需授权服务器即可使用 Spring Security 的内置 JWT 支持自己动手、Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器、spring security 4 多登录入口配置(spring-security-multiple-entry-points)的有用知识。

本文目录一览:

Spring Security MultiHttpSecurity配置,这样我就可以执行两种身份验证。JWT令牌和会话Cookie

Spring Security MultiHttpSecurity配置,这样我就可以执行两种身份验证。JWT令牌和会话Cookie

我已经为我的应用程序安装了Spring Security
Cookie机制,现在仅针对API,我需要添加基于JWT令牌的身份验证机制。我正在使用带有两个嵌套类的Spring
Security的MultiHttpSecurityConfiguration。

会话和JWT令牌机制是否应该一起包含在一个应用程序中是一个完全不同的问题,我需要实现两件事。

  1. Spring Security的基于cookie的基于会话的身份验证将像以前一样工作。

  2. 需要为API添加身份验证标头

    package com.leadwinner.sms.config;    import java.util.Collections;    import org.slf4j.Logger;    import org.slf4j.LoggerFactory;    import org.springframework.beans.factory.annotation.Autowired;    import org.springframework.beans.factory.annotation.Qualifier;    import org.springframework.context.annotation.Bean;    import org.springframework.context.annotation.ComponentScan;    import org.springframework.context.annotation.Configuration;    import org.springframework.core.annotation.Order;    import org.springframework.security.authentication.AuthenticationManager;    import org.springframework.security.authentication.ProviderManager;    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;    import org.springframework.security.config.annotation.web.builders.HttpSecurity;    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;    import org.springframework.security.config.http.SessionCreationPolicy;    import org.springframework.security.core.userdetails.UserDetailsService;    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;    import org.springframework.security.crypto.password.PasswordEncoder;    import org.springframework.security.web.authentication.AuthenticationSuccessHandler;    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;    import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;    import com.leadwinner.sms.CustomAuthenticationSuccessHandler;    import com.leadwinner.sms.CustomLogoutSuccessHandler;    import com.leadwinner.sms.config.jwt.JwtAuthenticationProvider;    import com.leadwinner.sms.config.jwt.JwtAuthenticationTokenFilter;    import com.leadwinner.sms.config.jwt.JwtSuccessHandler;    @EnableWebSecurity    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)    @ComponentScan(basePackages = "com.leadwinner.sms")    public class MultiHttpSecurityConfig {        @Autowired        @Qualifier("userServiceImpl")        private UserDetailsService userServiceImpl;        @Autowired        private JwtAuthenticationProvider authenticationProvider;        @Autowired        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {            auth.userDetailsService(userServiceImpl).passwordEncoder(passwordEncoder());        }        @Bean        public PasswordEncoder passwordEncoder() {            return  new BCryptPasswordEncoder();        }        @Bean        public AuthenticationManager authenticationManager() {            return new ProviderManager(Collections.singletonList(authenticationProvider));        }        @Configuration        @Order(1)        public static class JwtSecurityConfig extends WebSecurityConfigurerAdapter {             @Autowired             private JwtAuthenticationTokenFilter jwtauthFilter;            @Override            public void configure(HttpSecurity http) throws Exception {            http.csrf().disable()                .antMatcher("/web/umgmt/**").authorizeRequests()                .antMatchers("/web/umgmt/**").authenticated()                .and()                .addFilterBefore(jwtauthFilter, UsernamePasswordAuthenticationFilter.class);             http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);            }        }        @Configuration        @Order(2)        public static class SecurityConfig extends WebSecurityConfigurerAdapter {            private  final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);            @Bean            public CustomAuthenticationEntryPoint getBasicAuthEntryPoint() {                return new CustomAuthenticationEntryPoint();            }            @Override            public void configure(HttpSecurity http) throws Exception {                logger.info("http configure");                http                .antMatcher("/**").authorizeRequests()                          .antMatchers("/login/authenticate").permitAll()                        .antMatchers("/resources/js/**").permitAll()                        .antMatchers("/resources/css/**").permitAll()                        .antMatchers("/resources/images/**").permitAll()                        .antMatchers("/web/initial/setup/**").permitAll()                        .antMatchers("/dsinput/**").permitAll().antMatchers("/dsoutput/**").permitAll()                                         .and()                    .formLogin()                        .loginPage("/login").usernameParameter("employeeId").passwordParameter("password")                        .successForwardUrl("/dashboard")                        .defaultSuccessUrl("/dashboard", true)                        .successHandler(customAuthenticationSuccessHandler())                        .failureForwardUrl("/logout")                        .loginProcessingUrl("/j_spring_security_check")                        .and().logout()                        .logoutSuccessUrl("/logout").logoutUrl("/j_spring_security_logout")                        .logoutSuccessHandler(customLogoutSuccessHandler())                        .permitAll()                        .invalidateHttpSession(true)                        .deleteCookies("JSESSIONID")                        .and().sessionManagement()                        .sessionFixation().none()                        .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)                        .invalidSessionUrl("/logout")                        .and().exceptionHandling().accessDeniedPage("/logout").and().csrf().disable();                http.authorizeRequests().anyRequest().authenticated();            }            @Bean            public AuthenticationSuccessHandler customAuthenticationSuccessHandler() {                return new CustomAuthenticationSuccessHandler();            }            @Bean            public LogoutSuccessHandler customLogoutSuccessHandler() {                return new CustomLogoutSuccessHandler();            }        }    }

JwtAuthenticationTokenFilter.java

    package com.leadwinner.sms.config.jwt;    import java.io.IOException;    import javax.servlet.FilterChain;    import javax.servlet.ServletException;    import javax.servlet.http.HttpServletRequest;    import javax.servlet.http.HttpServletResponse;    import org.springframework.beans.factory.annotation.Autowired;    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;    import org.springframework.security.core.context.SecurityContextHolder;    import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;    import org.springframework.web.filter.OncePerRequestFilter;    public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {        @Autowired        private JwtTokenUtil jwtTokenUtil;        @Override        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)                throws ServletException, IOException {            final String header = request.getHeader("Authorization");            if (header != null && header.startsWith("Bearer ")) {                String authToken = header.substring(7);                System.out.println(authToken);                try {                    String username = jwtTokenUtil.getUsernameFromToken(authToken);                    if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {                        if (jwtTokenUtil.validateToken(authToken, username)) {                            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(                                    username, null, null);                            usernamePasswordAuthenticationToken                                    .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));                            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);                        }                    }                } catch (Exception e) {                    System.out.println("Unable to get JWT Token, possibly expired");                }            }            chain.doFilter(request, response);        }    }

JwtTokenUtil.java

    package com.leadwinner.sms.config.jwt;    import java.io.Serializable;    import java.util.Date;    import java.util.HashMap;    import java.util.Map;    import java.util.function.Function;    import org.springframework.stereotype.Component;    import io.jsonwebtoken.Claims;    import io.jsonwebtoken.Jwts;    import io.jsonwebtoken.SignatureAlgorithm;    @Component    public class JwtTokenUtil implements Serializable {        private static final long serialVersionUID = 8544329907338151549L;        public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60;        private String secret = "my-secret";        public String getUsernameFromToken(String token) {            return getClaimFromToken(token, Claims::getSubject);        }        public Date getExpirationDateFromToken(String token) {            return getClaimFromToken(token, Claims::getExpiration);        }        public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {            final Claims claims = getAllClaimsFromToken(token);            return claimsResolver.apply(claims);        }        private Claims getAllClaimsFromToken(String token) {            return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();        }        private Boolean isTokenExpired(String token) {            final Date expiration = getExpirationDateFromToken(token);            return expiration.before(new Date());        }        public String generateToken(String username) {            Map<String, Object> claims = new HashMap<>();            return doGenerateToken(claims, username);        }        private String doGenerateToken(Map<String, Object> claims, String subject) {            return "Bearer "                    + Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))                            .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))                            .signWith(SignatureAlgorithm.HS512, secret).compact();        }        public Boolean validateToken(String token, String usernameFromToken) {            final String username = getUsernameFromToken(token);            return (username.equals(usernameFromToken) && !isTokenExpired(token));        }    }

看来JwtSecurityConfig筛选器现在并未应用于我提到的路径。任何帮助将不胜感激。

我已经读过这个问题。我也一样。

带有Spring Boot的SpringSecurity:将基本身份验证与JWT令牌身份验证混合

编辑:添加了JwtAuthenticationTokenFilter,JwtTokenUtil

答案1

小编典典

我有你的要求

  1. 您需要在请求标头(针对每个请求)中公开应通过JWT令牌访问的API。

  2. Web应用程序也应通过基于表单的身份验证机制来保护,该机制应基于http会话进行工作。

您可以通过两个身份验证过滤器来实现。

过滤器-1 :用于Rest
API(JwtAuthTokenFilter),该API应该是无状态的,并由每次请求中发送的Authorization令牌标识。
过滤器2
:您需要另一个过滤器(UsernamePasswordAuthenticationFilter)默认情况下,如果通过进行配置,spring-
security将提供此过滤器http.formLogin()。在这里,每个请求都由JSESSIONID关联的session(cookie)标识。如果请求中不包含有效的会话,则它将被重定向到身份验证入口点(例如:login-
page)。

推荐的网址格式

api-url-pattern    = "/api/**" [strictly for @order(1)]webApp-url-pattern = "/**" [ wild card "/**" always used for higer order otherwise next order configuration becomes dead configuration]

方法

  • 定义主配置类 @EnableWebSecurity

  • 创建两个内部静态类,它们应WebSecurityConfigurerAdapter使用@Configuration和@Order进行扩展和注释。在此,REST API配置的顺序应为1,Web应用程序配置的顺序应大于1

  • 请参阅 此链接中的我的答案以获取更多详细信息 ,其中 详细 解释了必要的代码。如果需要,请随时从github存储库中请求可下载的链接。

限制
在这里,两个过滤器将并排(平行)工作。我的意思是从Web应用程序开始,即使用户通过会话进行了身份验证,但如果没有JWT令牌,他也无法访问API。

编辑
OP的要求,即他不想定义任何角色,但允许经过身份验证的用户进行API访问。根据他的要求修改了以下配置。

http.csrf().disable().antMatcher("/web/umgmt/**").authorizeRequests().antMatcher("/web/umgmt/**").authenticated() // use this

Java Spring Security配置-多个身份验证提供程序

Java Spring Security配置-多个身份验证提供程序

如何解决Java Spring Security配置-多个身份验证提供程序?

也许这会帮助你:

@Configuration
@EnableWebSecurity
@Profile("container")
public class XSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private AuthenticationProvider authenticationProvider;

@Autowired
private AuthenticationProvider authenticationProviderDB;

@Override
@Order(1)

protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider);
}

@Order(2)
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProviderDB);
}

@Override
  public void configure(WebSecurity web) throws Exception {
    web
      .ignoring()
         .antMatchers("/scripts/**","/styles/**","/images/**","/error/**");
  }

@Override
public void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .antMatchers("/rest/**").authenticated()
            .antMatchers("/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .successHandler(new AuthenticationSuccessHandler() {
                @Override
                public void onAuthenticationSuccess(
                        HttpServletRequest request,
                        HttpServletResponse response,
                        Authentication a) throws IOException, servletexception {
                            //To change body of generated methods,
                            response.setStatus(HttpServletResponse.SC_OK);
                        }
            })
            .failureHandler(new AuthenticationFailureHandler() {

                @Override
                public void onAuthenticationFailure(
                        HttpServletRequest request,
                        HttpServletResponse response,
                        AuthenticationException ae) throws IOException, servletexception {
                            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                        }
            })
            .loginProcessingUrl("/access/login")
            .and()
            .logout()
            .logoutUrl("/access/logout")                
            .logoutSuccessHandler(new logoutSuccessHandler() {
                @Override
                public void onlogoutSuccess(
                        HttpServletRequest request, 
                        HttpServletResponse response, 
                        Authentication a) throws IOException, servletexception {
                    response.setStatus(HttpServletResponse.SC_NO_CONTENT);
                }
            })
            .invalidateHttpSession(true)
            .and()
            .exceptionHandling()
            .authenticationEntryPoint(new Http403ForbiddenEntryPoint())
            .and()
            .csrf()//disabled CSRF protection
            .disable();
    }
} 

在Spring Boot中,这对我有用:

每个身份验证提供程序都按顺序进行测试。如果通过,则跳过其后面的身份验证提供程序

auth.userDetailsService(userDetailsService)...

然后:

auth.ldapAuthentication()....
@EnableRedisHttpSession
@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private CustomUserDetailsService userDetailsService;

@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {

    //each Authentication provider is tested in order
    //if one passes then its following Authentication providers are skipped

    //DataBase Authentication
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordencoder());



    LdapContextSource ldapContextSource = new LdapContextSource();


    ldapContextSource.setUrl("ldap://192.168.XXX.XXX:389");
    ldapContextSource.setBase("dc=companyname,dc=com");
    ldapContextSource.setUserDn("cn=user,cn=testgroup,ou=Test,dc=companyname,dc=com");
    ldapContextSource.setPassword("user1234");
    ldapContextSource.afterPropertiesSet();



    //LDAP Authentication
    auth.ldapAuthentication()
        //The {0} in the (uid={0}) will be replaced by the username entered in the form.
        .userSearchBase("ou=Group")
        .userSearchFilter("uid={0}")

        //.userDnPatterns("uid={0},ou=people")//does the same thing 

        //Specifies where the search for Roles start
        //.groupSearchBase("ou=mathematicians")
        //in groups we search for member
        //.groupSearchFilter("member={0}")
        //.contextSource().ldif("classpath:test-server.ldif");

    .contextSource(ldapContextSource);



}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests()


            .antMatchers("/hello").access("hasRole(''ROLE_ADMIN'')")
            .antMatchers("/index").fullyAuthenticated()
            .antMatchers("/").fullyAuthenticated()
            .antMatchers("/home").fullyAuthenticated()
            .anyRequest().permitAll()

            .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .usernameParameter("username").passwordParameter("password")
            .and()
            .logout()
                .logoutSuccessUrl("/login?logout")
                .permitAll()
            .and()
                .exceptionHandling()
                .accessDeniedPage("/403")
            .and()
                .csrf()
                .disable();



}

@Bean(name = "passwordEncoder")
public PasswordEncoder passwordencoder() {
    return new BCryptPasswordEncoder();
}
}

解决方法

在Spring Security中,有多个身份验证提供程序的参考,但是找不到Java config中的示例。

以下链接给出了XML表示法: Spring Security中的多个身份验证提供程序

我们需要使用LDAP或DB进行身份验证

下面是我们的示例代码:

@Configuration
@EnableWebSecurity
public class XSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AuthenticationProvider authenticationProvider;

    @Autowired
    private AuthenticationProvider authenticationProviderDB;


    @Override
    @Order(1)

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }


    @Order(2)
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProviderDB);
    }

    @Override
      public void configure(WebSecurity web) throws Exception {
        web
          .ignoring()
             .antMatchers("/scripts/**","/styles/**","/images/**","/error/**");
      }
    ______

    @Override
    @Order(1)
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
        .authorizeRequests()
            .antMatchers("/","/logout","/time").permitAll()
                    .antMatchers("/admin").hasRole("ADMIN")         
                        .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/index")
            .loginProcessingUrl("/perform_login")
            .usernameParameter("email")
            .passwordParameter("password")
            .failureUrl("/index?failed=true")
            .defaultSuccessUrl("/summary",true)
            .permitAll()
            .and()
         .logout().logoutUrl("/logout")
                  .logoutSuccessUrl("/index?logout=true").permitAll()
            .and()
            .exceptionHandling().accessDeniedPage("/error403")
        .and().authenticationProvider(authenticationProvider);

    }

    @Order(1)
    protected void configureDB(HttpSecurity http) throws Exception {
        http.csrf().disable()
        .authorizeRequests()
            .antMatchers("/","/logout").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/index")
            .loginProcessingUrl("/perform_login")
            .usernameParameter("email")
            .passwordParameter("password")
            .failureUrl("/index?failed=true")
            .defaultSuccessUrl("/summary",true)
            .permitAll()
            .authenticationProvider(authenticationProviderDB)
    //This line giving compilation error stating authenticationProvider is not available in formloginconfigurer

         .and()
         .logout().logoutUrl("/logout")
                  .logoutSuccessUrl("/index?logout=true").permitAll()
            .and()
            .exceptionHandling().accessDeniedPage("/error403");
    }

}

Spring Boot HttpSecurity - @PreAuthorize - 如何设置 AuthenticationFilter? 使用 Spring Security 的内置 JWT 支持无需授权服务器即可使用 Spring Security 的内置 JWT 支持自己动手

Spring Boot HttpSecurity - @PreAuthorize - 如何设置 AuthenticationFilter? 使用 Spring Security 的内置 JWT 支持无需授权服务器即可使用 Spring Security 的内置 JWT 支持自己动手

JwtAuthorizationFilter 的目的应该是设置 Authentication 的授予权限。那么,Spring Security 的默认方法 security 就足够了。

您有几个选择:

使用 Spring Security 的内置 JWT 支持

如果 JWT 是由授权服务器铸造的,那么 Spring Security's default JWT support 可能就足够了。 Spring Security 附带 BearerTokenAuthenticationFilterJwtAuthenticationProvider。过滤器将解析 Authorization 标头以获取令牌,提供程序将验证令牌并构建基于 Authenticationscope 声明的 scp。在这种情况下,您可以执行类似 @PreAuthorize("hasAuthority('SCOPE_ADMIN')") 的操作。

如果您需要自定义如何将 JWT 声明转换为 GrantedAuthority,那么您可以发布一个 JwtAuthenticationConverter @Bean

有关完整的设置详细信息,请查看 Spring Security's OAuth 2.0 Resource Server sample。不过,基本上,您的配置如下所示:

http
    .authorizeRequests((authz) -> authz
        .anyRequest().authenticated()
    )
    .oauth2ResourceServer((oauth2) -> oauth2
        .jwt(Customizer.withDefaults())
    );

无需授权服务​​器即可使用 Spring Security 的内置 JWT 支持

Spring Security 的现有支持在设计时考虑了授权服务器,但这不是必需的。

您可以改为让您的应用程序 mint self-signed tokens。

自己动手

您可以保留您的 JwtAuthorizationFilter,但尚不清楚 Spring Security 现有支持为何不足。要添加过滤器,您只需执行 addFilterBefore(myFilter,BearerTokenAuthenticationFilter.class)。您可以查看 BearerTokenAuthenicationFilter 作为创建自己的过滤器时应考虑的一些事项的示例。

Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器

Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器

标题文字 #### 概要

之前的两篇文章,讲述了Spring Security 结合 OAuth2 、JWT 的使用,这一节要求对 OAuth2、JWT 有了解,若不清楚,先移步到下面两篇提前了解下。

Spring Boot Security 整合 OAuth2 设计安全API接口服务

Spring Boot Security 整合 JWT 实现 无状态的分布式API接口

这一篇我们来实现 支持 JWT令牌 的授权服务器。

优点

使用 OAuth2 是向认证服务器申请令牌,客户端拿这令牌访问资源服务服务器,资源服务器校验了令牌无误后,如果资源的访问用到用户的相关信息,那么资源服务器还需要根据令牌关联查询用户的信息。

使用 JWT 是客户端通过用户名、密码 请求服务器获取 JWT,服务器判断用户名和密码无误之后,可以将用户信息和权限信息经过加密成 JWT 的形式返回给客户端。在之后的请求中,客户端携带 JWT 请求需要访问的资源,如果资源的访问用到用户的相关信息,那么就直接从JWT中获取到。

所以,如果我们在使用 OAuth2 时结合JWT ,就能节省集中式令牌校验开销,实现无状态授权认证。

快速上手

项目说明

工程名 端口 作用
jwt-authserver 8080 授权服务器
jwt-resourceserver 8081 资源服务器

授权服务器

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-jwt</artifactId>
    <version>1.0.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

WebSecurityConfig

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
             authorizeRequests().antMatchers("/**").permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
            .withUser("user").password("123456").roles("USER");
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return charSequence.toString();
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return Objects.equals(charSequence.toString(),s);
            }
        };
    }

}

为了方便,使用内存模式,在内存中创建一个用户 user 密码 123456。

OAuth2AuthorizationServer

/**
 * 授权服务器
 */
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    /**
     * 注入AuthenticationManager ,密码模式用到
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     * 对Jwt签名时,增加一个密钥
     * JwtAccessTokenConverter:对Jwt来进行编码以及解码的类
     */
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("test-secret");
        return converter;
    }

    /**
     * 设置token 由Jwt产生,不使用默认的透明令牌
     */
    @Bean
    public JwtTokenStore jwtTokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager)
                .tokenStore(jwtTokenStore())
                .accessTokenConverter(accessTokenConverter());
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("clientapp")
                .secret("123")
                .scopes("read")
                //设置支持[密码模式、授权码模式、token刷新]
                .authorizedGrantTypes(
                        "password",
                        "authorization_code",
                        "refresh_token");
    }


}

资源服务器

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-jwt</artifactId>
    <version>1.0.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

HelloController

@RestController("/api")
public class HelloController {

    @PostMapping("/api/hi")
    public String say(String name) {
        return "hi , " + name;
    }

}

OAuth2ResourceServer

/**
 * 资源服务器
 */
@Configuration
@EnableResourceServer
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest().authenticated().and()
            .requestMatchers().antMatchers("/api/**");
    }
}

application.yml

server:
  port: 8081

security:
  oauth2:
    resource:
      jwt:
        key-value: test-secret

参数说明:

  • security.oauth2.resource.jwt.key-value:设置签名key 保持和授权服务器一致。
  • security.oauth2.resource.jwt:项目启动过程中,检查到配置文件中有

security.oauth2.resource.jwt 的配置,就会生成 jwtTokenStore 的 bean,对令牌的校验就会使用 jwtTokenStore 。

验证

请求令牌

curl -X POST --user ''clientapp:123'' -d ''grant_type=password&username=user&password=123456'' http://localhost:8080/oauth/token

返回JWT令牌

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTQ0MzExMDgsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiOGM0YWMyOTYtMDQwYS00Y2UzLTg5MTAtMWJmNjZkYTQwOTk3IiwiY2xpZW50X2lkIjoiY2xpZW50YXBwIiwic2NvcGUiOlsicmVhZCJdfQ.YAaSRN0iftmlR6Khz9UxNNEpHHn8zhZwlQrCUCPUmsU",
    "token_type": "bearer",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ1c2VyIiwic2NvcGUiOlsicmVhZCJdLCJhdGkiOiI4YzRhYzI5Ni0wNDBhLTRjZTMtODkxMC0xYmY2NmRhNDA5OTciLCJleHAiOjE1NTY5Nzk5MDgsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiJdLCJqdGkiOiI0ZjA5M2ZjYS04NmM0LTQxZWUtODcxZS1kZTY2ZjFhOTI0NTAiLCJjbGllbnRfaWQiOiJjbGllbnRhcHAifQ.vvAE2LcqggBv8pxuqU6RKPX65bl7Zl9dfcoIbIQBLf4",
    "expires_in": 43199,
    "scope": "read",
    "jti": "8c4ac296-040a-4ce3-8910-1bf66da40997"
}

携带JWT令牌请求资源

curl -X POST -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTQ0MzExMDgsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiOGM0YWMyOTYtMDQwYS00Y2UzLTg5MTAtMWJmNjZkYTQwOTk3IiwiY2xpZW50X2lkIjoiY2xpZW50YXBwIiwic2NvcGUiOlsicmVhZCJdfQ.YAaSRN0iftmlR6Khz9UxNNEpHHn8zhZwlQrCUCPUmsU" -d ''name=zhangsan'' http://localhost:8081/api/hi

返回

hi , zhangsan

源码

https://github.com/gf-huanchu...

欢迎扫码或微信搜索公众号《程序员果果》关注我,关注有惊喜~

spring security 4 多登录入口配置(spring-security-multiple-entry-points)

spring security 4 多登录入口配置(spring-security-multiple-entry-points)

详见转贴文章

关于Spring Security MultiHttpSecurity配置,这样我就可以执行两种身份验证。JWT令牌和会话Cookie的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于Java Spring Security配置-多个身份验证提供程序、Spring Boot HttpSecurity - @PreAuthorize - 如何设置 AuthenticationFilter? 使用 Spring Security 的内置 JWT 支持无需授权服务器即可使用 Spring Security 的内置 JWT 支持自己动手、Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器、spring security 4 多登录入口配置(spring-security-multiple-entry-points)的相关信息,请在本站寻找。

本文标签: