2017-06-01 18 views
9

Tôi đã tạo ứng dụng Spring-Boot hoạt động với xác thực jwt.Làm cách nào để triển khai Xác thực cơ bản với xác thực JWT trong Spring Boot?

<?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> 

Tôi muốn có một xác thực cơ bản, khi tôi sử dụng Swagger Tôi muốn có một popup với khi tôi bấm vào Try Out nút

Ví dụ:

enter image description here

làm thế nào có thể sử dụng hai bộ lọc bảo mật (cơ sở biểu mẫu, mã thông báo JWT) của bảo mật mùa xuân trên cùng một điểm cuối?

WebSecurityConfig

@Configuration 
@EnableWebSecurity 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

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

     http.exceptionHandling().and().anonymous().and().servletApi().and().authorizeRequests() 

       // Allow anonymous resource requests 
       .antMatchers("/swagger-ui.html").permitAll().antMatchers("/").permitAll() 
       .antMatchers("/webjars/springfox-swagger-ui/**").permitAll().antMatchers("/swagger-resources/**") 
       .permitAll().antMatchers("/v2/api-docs").permitAll().antMatchers("/favicon.ico").permitAll() 
       .antMatchers("**/*.html").permitAll().antMatchers("**/*.css").permitAll().antMatchers("**/*.js") 
       .permitAll() 

       // Allow anonymous logins 
       .antMatchers("/user/User").permitAll().antMatchers("/locality/**").hasAuthority("Admin") 
       .antMatchers("/category/**").hasAuthority("Admin").antMatchers("/item").hasAuthority("Item") 
       .antMatchers("/item/userItems").hasAuthority("Item").antMatchers("item/lookFor").permitAll() 
       .antMatchers("item/items").hasAuthority("User") 

       // All other request need to be authenticated 
       .anyRequest().authenticated().and() 
       // And filter other requests to check the presence of JWT in 
       // header 
       .addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); 
    } 

    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 

     // Créer un compte par défaut 
     auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN"); 
    } 
} 

TokenAuthenticationService

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"); 
    } 

} 

JWTLoginFilter

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()); 
    } 
} 

JWTAuthenticationFilter

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); 
    } 
} 

AccountCredentials

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; 
    } 

} 
+1

Sơ đồ xác thực hiện tại của bạn là gì? Bạn lưu trữ thông tin người dùng của mình ở đâu? –

+0

@MarcTarin Tôi không lưu trữ bất cứ thứ gì. – Mercer

Trả lời

6

Bạn sẽ phải tạo ra hai WebSecurityConfigurerAdapter cấu hình khác nhau với các URL gốc khác nhau. Nếu các URL trùng lặp (ví dụ: /admin and /**) thì bạn sẽ cần xác định mức độ ưu tiên bằng cách sử dụng chú thích @Order trên cấu hình.

Dưới đây là ví dụ hoạt động cho xác thực dựa trên Mẫu cơ bản và HTTP.

https://github.com/ConsciousObserver/TestMultipleLoginPagesFormAndBasic.git

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(); 
    } 
} 

Lưu ý: Vì các trang đăng nhập không phải là từ các ứng dụng khác nhau, họ chia sẻ SecurityContextHolder hoặc bối cảnh an ninh. Vì vậy, nếu bạn đăng nhập từ một trang đăng nhập và sau đó cố gắng truy cập tài nguyên được bảo vệ của trang khác, bạn sẽ không được chuyển hướng đến trang đăng nhập tiếp theo. Thay vào đó, bạn sẽ nhận được 403 (tùy thuộc vào vai trò được chỉ định bởi các trang đăng nhập khác nhau). Tại một thời điểm chỉ có thể duy trì một phiên đăng nhập.

Các vấn đề liên quan