本文介绍basic auth和JWT验证结合
目录结构
依赖
io.jsonwebtoken jjwt 0.9.1 com.auth0 auth0 1.8.0 com.auth0 auth0-spring-security-api 1.1.0 org.springframework.boot spring-boot-starter-security org.json json 20180813 org.glassfish javax.xml.bind 10.0-b28
config配置文件WebSecurityConfig
package com.springlearn.learn.config;import com.springlearn.learn.filter.JWTAuthenticationFilter;import com.springlearn.learn.filter.JWTLoginFilter;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.http.HttpMethod;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.core.userdetails.User;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;import org.springframework.web.servlet.config.annotation.CorsRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class WebSecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and().csrf().disable(); // 所有的请求都要验证 http.authorizeRequests() .antMatchers("/").permitAll() // 访问 "/" 无需验证 .antMatchers(HttpMethod.POST, "/login").permitAll() // 访问 "/login" 无需token即可进入 .antMatchers(HttpMethod.GET, "/login").permitAll() .anyRequest() .authenticated() .and() .addFilterBefore( // 添加验证过滤器 new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class ) .addFilterBefore( new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class ); } @Bean public BCryptPasswordEncoder passwordEncoder() { BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); return bCryptPasswordEncoder; } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { String password = "234"; String encrytedPassword = this.passwordEncoder().encode(password); System.out.println("Encoded password = " + encrytedPassword); // 这里使用写死的验证,你可以在这里访问数据库 InMemoryUserDetailsManagerConfigurer mngConfig = auth.inMemoryAuthentication(); UserDetails u1 = User.withUsername("yejiawei").password(encrytedPassword).roles("ADMIN").build(); UserDetails u2 = User.withUsername("donglei").password(encrytedPassword).roles("USER").build(); mngConfig.withUser(u1); mngConfig.withUser(u2); } @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("*").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*") .allowedHeaders("*"); }}
filter过滤器JWTLoginFilter
package com.springlearn.learn.filter;import java.io.IOException;import java.util.Collections;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.stream.Collectors;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.springlearn.learn.service.TokenAuthenticationService;import org.json.JSONObject;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.Authentication;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;import org.springframework.security.web.util.matcher.AntPathRequestMatcher;public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter{ public JWTLoginFilter(String url, AuthenticationManager authManager) { super(new AntPathRequestMatcher(url)); setAuthenticationManager(authManager); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { // get方式获取参数 // String username = request.getParameter("username"); // String password = request.getParameter("password"); // post方式获取数据 String s = request.getReader().lines().collect(Collectors.joining(System.lineSeparator())); JSONObject jsonObject = new JSONObject(s); HashMap result = new HashMap (); String key = null; Iterator keys = jsonObject.keys(); while(keys.hasNext()) { key = (String) keys.next(); result.put(key, jsonObject.getString(key)); } System.out.printf("JWTLoginFilter.attemptAuthentication: username/password= %s,%s", result.get("username"), result.get("password")); System.out.println(); return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(result.get("username"), result.get("password"), Collections.emptyList())); } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { System.out.println("JWTLoginFilter.successfulAuthentication:"); // Write Authorization to Headers of Response. TokenAuthenticationService.addAuthentication(response, authResult.getName()); String authorizationString = response.getHeader("Authorization"); System.out.println("Authorization String=" + authorizationString); } @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_OK); response.getOutputStream().println((new JSONObject(){ { put("status", 500); put("message", "Internal Server Error!!!"); put("result", JSONObject.NULL); }}).toString()); }}
filter过滤器JWTAuthenticationFilter
package com.springlearn.learn.filter;import java.io.IOException;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import com.springlearn.learn.service.TokenAuthenticationService;import org.springframework.security.core.Authentication;import org.springframework.security.core.context.SecurityContextHolder;import org.springframework.web.filter.GenericFilterBean;public class JWTAuthenticationFilter extends GenericFilterBean { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("JWTAuthenticationFilter.doFilter"); Authentication authentication = TokenAuthenticationService.getAuthentication((HttpServletRequest) servletRequest); SecurityContextHolder.getContext().setAuthentication(authentication); filterChain.doFilter(servletRequest, servletResponse); }}
service中的TokenAuthenticationService
package com.springlearn.learn.service;import java.io.IOException;import java.util.Collections;import java.util.Date;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.json.JSONObject;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.Authentication;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;public class TokenAuthenticationService { static final long _expiretime = 864_000_000; static final String _secret = "ThisIsASecret"; static final String _token_prefix = "Bearer"; static final String _header_string = "Authorization"; public static void addAuthentication(HttpServletResponse res, String username) throws IOException { String JWT = Jwts.builder() .setSubject(username) .setExpiration(new Date(System.currentTimeMillis() + _expiretime)) .signWith(SignatureAlgorithm.HS512, _secret).compact(); res.addHeader(_header_string, _token_prefix + " " + JWT); res.setContentType("application/json"); res.setStatus(HttpServletResponse.SC_OK); res.getOutputStream().println((new JSONObject(){ { put("status", 0); put("message", ""); put("result", JWT); }}).toString()); } public static Authentication getAuthentication(HttpServletRequest request) { String token = request.getHeader(_header_string); if (token != null) { // parse the token. String user = Jwts.parser().setSigningKey(_secret).parseClaimsJws(token.replace(_token_prefix, "")).getBody() .getSubject(); return user != null ? new UsernamePasswordAuthenticationToken(user, null, Collections.emptyList()) : null; } return null; }}
启动文件DemoApplication
package com.springlearn.learn;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}
Controller中的TestController
package com.springlearn.learn.controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class TestController { @ResponseBody @RequestMapping(value = "/AuthTest", method = RequestMethod.GET) public String AuthTest(HttpServletRequest request, HttpServletResponse response) { return "OK"; } @ResponseBody @RequestMapping(value = "/login", method = RequestMethod.GET) public String Login(@RequestBody Object user, HttpServletRequest request, HttpServletResponse response) { return "OK"; }}
前端测试
Document