在用spring + mybatis 作項目。以前安全驗證用basic 方式如今想換成jwt。java
jwt :web
JWS模式對這個內容進行了數字化簽名。這個內容被用來存放JWT的聲明.服務端簽名出JWT而且發送到客戶端,並在用戶成功認證後進行應答。服務器指望客戶端在下次請求的時候將JWS做爲請求的一部分,發送回服務端。算法
若是咱們處理的客戶端是欺騙者則麼辦?這就是簽名(signature)須要出場的地方了。簽名攜帶了完整的可驗證的信息。換句話說,服務器能夠確認,接收到的JWT聲明裏的JWS是沒有通過欺騙客戶端、中間者進行修改的。spring
服務端經過驗證消息的簽名來確保客戶端沒有修改聲明。若是服務端檢測到任何修改,能夠採起適當的動做(拒絕此次請求或者鎖定客戶端之類的)api
客戶端一樣能夠驗證簽名,爲了作到這點,客戶端也須要服務端的secret(密鑰)(若是這個JWT簽名是HMAC算法),或者須要服務端對公鑰(若是這個WJT是數字化簽名)安全
特別注意:對於JWS,荷載(聲明部分)沒有進行加密,因此,不要發送任何敏感信息.服務器
首先在web.xml 中session
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring-mybatis.xml /WEB-INF/spring-security.xml classpath:applicationContext.xml </param-value> </context-param> <!-- Security --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>fly.fky</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>fly.fky</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
spring-sucurity.xmlmybatis
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.2.xsd"> <context:annotation-config /> <global-method-security pre-post-annotations="enabled" /> <beans:bean id="passwordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder"> <beans:constructor-arg value="ThisIsASecretSoChangeMe" /> </beans:bean> <!-- <authentication-manager id="authenticationManager" erase-credentials="false"> <authentication-provider user-service-ref="userService"> <password-encoder ref="passwordEncoder"></password-encoder> </authentication-provider> </authentication-manager> <http pattern="/**" entry-point-ref="unauthorizedEntryPoint" create-session="stateless"> <csrf disabled="true" /> <custom-filter before="FORM_LOGIN_FILTER" ref="jwtAuthenticationFilter" /> </http> <beans:bean id="jwtAuthenticationFilter" class="fly.fky.restapi.security.JwtAuthenticationFilter"> <beans:property name="authenticationManager" ref="authenticationManager" /> <beans:property name="authenticationSuccessHandler" ref="jwtAuthenticationSuccessHandler" /> </beans:bean> <beans:bean id="unauthorizedEntryPoint" class="fly.fky.restapi.service.UnauthorizedEntryPoint" /> <beans:bean id="jwtAuthenticationSuccessHandler" class="fly.fky.restapi.security.JwtAuthenticationSuccessHandler" /> <!-- authentication manager --> <authentication-manager id="authenticationManager"> <authentication-provider ref="jwtAuthenticationProvider"> </authentication-provider> </authentication-manager> <beans:bean id="jwtAuthenticationProvider" class="fly.fky.restapi.security.JwtAuthenticationProvider" /> </beans:beans>
jwt filter 文件app
public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public JwtAuthenticationFilter() { super("/**"); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { String header = request.getHeader("Authorization"); if (header == null || !header.startsWith("Bearer ")) { throw new RestAPIAuthenticationException(MessageToClientFormat.formateMsg("No JWT token found in request headers")); } String authToken = header.substring(7); return JwtTokenUtil.getAuthentication(authToken); } }
JwtAuthenticationProvider
public class JwtAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { @Resource private UserService userService; @Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { if (authentication.getCredentials() == null) { logger.debug("Authentication failed: no credentials provided"); throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } String presentedPassword = authentication.getCredentials().toString(); if (!userService.isPasswordMatched(presentedPassword, userDetails.getPassword())) { logger.debug("Authentication failed: password does not match stored value"); throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } } @Override protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { return userService.loadUserByUsername(username); } }