Java 如何在Spring Boot中使用JWT身份验证实现基本身份验证?
我已经构建了一个Java 如何在Spring Boot中使用JWT身份验证实现基本身份验证?,java,spring-boot,spring-security,jwt,basic-authentication,Java,Spring Boot,Spring Security,Jwt,Basic Authentication,我已经构建了一个springboot应用程序,它可以与jwt身份验证一起工作 <?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
springboot
应用程序,它可以与jwt
身份验证一起工作
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.diplie</groupId>
<artifactId>rest-api</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.RC1</version>
</parent>
<properties>
<springfox-version>2.2.2</springfox-version>
<java.version>1.8</java.version>
<maven.test.skip>true</maven.test.skip>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>LATEST</version>
</dependency>
<!-- Swagger 2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox-version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox-version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>${project.parent.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>repository.springsource.milestone</id>
<name>SpringSource Milestone Repository</name>
<url>http://repo.springsource.org/milestone</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>repository.springsource.milestone</id>
<name>SpringSource Milestone Repository</name>
<url>http://repo.springsource.org/milestone</url>
</pluginRepository>
</pluginRepositories>
</project>
TokenAuthenticationService
JWTLoginFilter
JWTAuthenticationFilter
账户凭证
您必须使用不同的根URL创建两种不同的
websecurityConfigureAdapter
配置。如果URL重叠(即/admin和/**
),则需要使用配置上的@Order
注释来定义优先级
下面是HTTP Basic和基于表单的身份验证的工作示例
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.diplie</groupId>
<artifactId>rest-api</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.RC1</version>
</parent>
<properties>
<springfox-version>2.2.2</springfox-version>
<java.version>1.8</java.version>
<maven.test.skip>true</maven.test.skip>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>LATEST</version>
</dependency>
<!-- Swagger 2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox-version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox-version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>${project.parent.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>repository.springsource.milestone</id>
<name>SpringSource Milestone Repository</name>
<url>http://repo.springsource.org/milestone</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>repository.springsource.milestone</id>
<name>SpringSource Milestone Repository</name>
<url>http://repo.springsource.org/milestone</url>
</pluginRepository>
</pluginRepositories>
</project>
注意:由于这些登录页面不是来自不同的应用程序,因此它们共享SecurityContextHolder或安全上下文。因此,如果您从一个登录页面登录,然后尝试转到另一个受保护的资源,则不会重定向到下一个登录页面。相反,您将获得403(取决于不同登录页面分配的角色)。一次只能维护一个登录会话。您当前的身份验证方案是什么?你的用户信息存储在哪里?@MarcTarin实际上我什么都不存储。
public class TokenAuthenticationService {
static ResourceBundle bundle = ResourceBundle.getBundle("application");
static void addAuthentication(HttpServletResponse res, String username) {
String JWT = Jwts.builder().setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + getExpirationTime()))
.signWith(SignatureAlgorithm.HS512, getSecret()).compact();
res.addHeader(getHeaderString(), getTokenPrefix() + " " + JWT);
}
static Authentication getAuthentication(HttpServletRequest request) {
String token = request.getHeader(getHeaderString());
if (token != null) {
// Analyse du jeton.
String user = Jwts.parser().setSigningKey(getSecret()).parseClaimsJws(token.replace(getTokenPrefix(), ""))
.getBody().getSubject();
return user != null ? new UsernamePasswordAuthenticationToken(user, null, emptyList()) : null;
}
return null;
}
/**
* @return the secret
*/
public static String getSecret() {
return bundle.getString("secret");
}
/**
* @return the expirationTime
*/
public static long getExpirationTime() {
return Long.valueOf(bundle.getString("expiration.time"));
}
/**
* @return the tokenPrefix
*/
public static String getTokenPrefix() {
return bundle.getString("token.prefix");
}
/**
* @return the headerString
*/
public static String getHeaderString() {
return bundle.getString("header.string");
}
}
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {
public JWTLoginFilter(String url, AuthenticationManager authManager) {
super(new AntPathRequestMatcher(url));
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException, IOException, ServletException {
AccountCredentials creds = new ObjectMapper().readValue(req.getInputStream(), AccountCredentials.class);
return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(creds.getUsername(),
creds.getPassword(), Collections.emptyList()));
}
@Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
Authentication auth) throws IOException, ServletException {
TokenAuthenticationService.addAuthentication(res, auth.getName());
}
}
public class JWTAuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
Authentication authentication = TokenAuthenticationService.getAuthentication((HttpServletRequest) request);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
}
}
public class AccountCredentials {
private String username;
private String password;
/**
*
*/
public AccountCredentials() {
super();
}
/**
* @return the username
*/
public String getUsername() {
return username;
}
/**
* @param username
* the username to set
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password
* the password to set
*/
public void setPassword(String password) {
this.password = password;
}
}
package com.test;
import javax.servlet.http.HttpSession;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@SpringBootApplication
public class TestMultipleLoginPagesApplication {
public static void main(String[] args) {
SpringApplication.run(TestMultipleLoginPagesApplication.class, args);
}
}
@Controller
class MvcController {
@RequestMapping(path="form/formLogin", method=RequestMethod.GET)
public String formLoginPage() {
return "formLogin";
}
@RequestMapping(path="form/formHome", method=RequestMethod.GET)
public String formHomePage() {
return "formHome";
}
@RequestMapping(path="basic/basicHome", method=RequestMethod.GET)
public String userHomePage() {
return "basicHome";
}
@RequestMapping(path="basic/logout", method=RequestMethod.GET)
public String userLogout(HttpSession session) {
session.invalidate();
return "basicLogout";
}
}
@Configuration
@Order(1)
class FormSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/form/**")
.authorizeRequests()
.anyRequest().hasRole("FORM_USER")
.and()
.formLogin()
.loginPage("/form/formLogin").permitAll()
.loginProcessingUrl("/form/formLoginPost").permitAll()
.defaultSuccessUrl("/form/formHome")
.and()
.logout().logoutUrl("/form/logout").logoutSuccessUrl("/form/formLogin")
.and()
.httpBasic().disable()
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password("test")
.roles("FORM_USER");
}
}
@Configuration
@Order(2)
class BasicAuthSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/basic/**")
.authorizeRequests()
.anyRequest().hasRole("BASIC_USER")
.antMatchers("/basic/logout").permitAll()
.and()
.httpBasic()
.and()
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("basic_user")
.password("test")
.roles("BASIC_USER");
}
}
@Configuration
@Order(3)
class RootUrlSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
/*
* Put any security expectations from the root URL here, currently everything is permitted.
* Since it's the last in the order /form/** and /basic/** have a priority over it.
*/
http.antMatcher("/**")
.authorizeRequests()
.anyRequest().permitAll();
}
}