在本文中,我们将详细介绍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
- 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
Cookie机制,现在仅针对API,我需要添加基于JWT令牌的身份验证机制。我正在使用带有两个嵌套类的Spring
Security的MultiHttpSecurityConfiguration。
会话和JWT令牌机制是否应该一起包含在一个应用程序中是一个完全不同的问题,我需要实现两件事。
Spring Security的基于cookie的基于会话的身份验证将像以前一样工作。
需要为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
小编典典我有你的要求
您需要在请求标头(针对每个请求)中公开应通过JWT令牌访问的API。
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配置-多个身份验证提供程序?
也许这会帮助你:
@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 支持自己动手
JwtAuthorizationFilter
的目的应该是设置 Authentication
的授予权限。那么,Spring Security 的默认方法 security 就足够了。
您有几个选择:
使用 Spring Security 的内置 JWT 支持
如果 JWT 是由授权服务器铸造的,那么 Spring Security's default JWT support 可能就足够了。 Spring Security 附带 BearerTokenAuthenticationFilter
和 JwtAuthenticationProvider
。过滤器将解析 Authorization
标头以获取令牌,提供程序将验证令牌并构建基于 Authentication
或 scope
声明的 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 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 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)的相关信息,请在本站寻找。
本文标签: