javascript
JWT Authentication Tutorial: An example using Spring Boot--转
原文地址:http://www.svlada.com/jwt-token-authentication-with-spring-boot/
Table of contents:
Introduction
This article will guide you on how you can implement JWT authentication with Spring Boot.
We will cover the following two scenarios:
PRE-requisites
Please check out the sample code/project from the following GitHub repository:?https://github.com/svlada/springboot-security-jwt?before going further reading the article.
This project is using H2 in-memory database to store sample user information. To make things easier I have created data fixtures and configured Spring Boot to automatically load them on the application startup (/jwt-demo/src/main/resources/data.sql).
Overall project structure is shown below:
+---main | +---java | | \---com | | \---svlada | | +---common | | +---entity | | +---profile | | | \---endpoint | | +---security | | | +---auth | | | | +---ajax | | | | \---jwt | | | | +---extractor | | | | \---verifier | | | +---config | | | +---endpoint | | | +---exceptions | | | \---model | | | \---token | | \---user | | +---repository | | \---service | \---resources | +---static | \---templatesAjax authentication
When we talk about Ajax authentication we usually refer to process where user is supplying credentials through JSON payload that is sent as a part of XMLHttpRequest.
In the first part of this tutorial Ajax authentication is implemented by following standard patterns found in the Spring Security framework.
Following is the list of components that we'll implement:
Before we get to the details of the implementation, let's look at the request/response authentication flow.
Ajax authentication request example
The Authentication API allows user to pass in credentials in order to receive authentication token.
In our example, client initiates authentication process by invoking Authentication API endpoint (/api/auth/login).
Raw HTTP request:
POST /api/auth/login HTTP/1.1 Host: localhost:9966 X-Requested-With: XMLHttpRequest Content-Type: application/json Cache-Control: no-cache{"username": "svlada@gmail.com","password": "test1234" }CURL:
curl -X POST -H "X-Requested-With: XMLHttpRequest" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{ "username": "svlada@gmail.com","password": "test1234" }' "http://localhost:9966/api/auth/login"Ajax authentication response example
If client supplied credentials are valid, Authentication API will respond with the HTTP response including the following details:
JWT Access token?- used to authenticate against protected API resources. It must be set in?X-Authorization?header.
JWT Refresh token?- used to acquire new Access Token. Token refresh is handled by the following API endpoint:?/api/auth/token.
Raw HTTP Response:
{"token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJzdmxhZGFAZ21haWwuY29tIiwic2NvcGVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1BSRU1JVU1fTUVNQkVSIl0sImlzcyI6Imh0dHA6Ly9zdmxhZGEuY29tIiwiaWF0IjoxNDcyMDMzMzA4LCJleHAiOjE0NzIwMzQyMDh9.41rxtplFRw55ffqcw1Fhy2pnxggssdWUU8CDOherC0Kw4sgt3-rw_mPSWSgQgsR0NLndFcMPh7LSQt5mkYqROQ","refreshToken": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJzdmxhZGFAZ21haWwuY29tIiwic2NvcGVzIjpbIlJPTEVfUkVGUkVTSF9UT0tFTiJdLCJpc3MiOiJodHRwOi8vc3ZsYWRhLmNvbSIsImp0aSI6IjkwYWZlNzhjLTFkMmUtNDg2OS1hNzdlLTFkNzU0YjYwZTBjZSIsImlhdCI6MTQ3MjAzMzMwOCwiZXhwIjoxNDcyMDM2OTA4fQ.SEEG60YRznBB2O7Gn_5X6YbRmyB3ml4hnpSOxqkwQUFtqA6MZo7_n2Am2QhTJBJA1Ygv74F2IxiLv0urxGLQjg" }JWT Access Token
JWT Access token can be used for authentication and authorization:
Decoded JWT Access token has three parts: Header, Claims and Signature as shown below:
Header
{"alg": "HS512" }Claims
{"sub": "svlada@gmail.com","scopes": ["ROLE_ADMIN","ROLE_PREMIUM_MEMBER"],"iss": "http://svlada.com","iat": 1472033308,"exp": 1472034208 }Signature (base64 encoded)
41rxtplFRw55ffqcw1Fhy2pnxggssdWUU8CDOherC0Kw4sgt3-rw_mPSWSgQgsR0NLndFcMPh7LSQt5mkYqROQJWT Refresh Token
Refresh token is long-lived token used to request new Access tokens. It's expiration time is greater than expiration time of Access token.
In this tutorial we'll use?jti?claim to maintain list of blacklisted or revoked tokens. JWT ID(jti) claim is defined by?RFC7519?with purpose to uniquely identify individual Refresh token.
Decoded Refresh token has three parts: Header, Claims and Signature as shown below:
Header
{"alg": "HS512" }Claims
{"sub": "svlada@gmail.com","scopes": ["ROLE_REFRESH_TOKEN"],"iss": "http://svlada.com","jti": "90afe78c-1d2e-4869-a77e-1d754b60e0ce","iat": 1472033308,"exp": 1472036908 }Signature (base64 encoded)
SEEG60YRznBB2O7Gn_5X6YbRmyB3ml4hnpSOxqkwQUFtqA6MZo7_n2Am2QhTJBJA1Ygv74F2IxiLv0urxGLQjgAjaxLoginProcessingFilter
First step is to extend?AbstractAuthenticationProcessingFilter?in order to provide custom processing of Ajax authentication requests.
De-serialization and basic validation of the incoming JSON payload is done in the?AjaxLoginProcessingFilter#attemptAuthentication?method. Upon successful validation of the JSON payload authentication logic is delegated to AjaxAuthenticationProvider class.
In case of a successful authentication?AjaxLoginProcessingFilter#successfulAuthentication?method is invoked.?
In case of failure authentication?AjaxLoginProcessingFilter#unsuccessfulAuthentication?method is invoked.
AjaxAuthenticationProvider
Responsibility of the AjaxAuthenticationProvider class is to:
AjaxAwareAuthenticationSuccessHandler
We'll implement AuthenticationSuccessHandler interface that is called when client has been successfully authenticated.
AjaxAwareAuthenticationSuccessHandler class is our custom implementation of AuthenticationSuccessHandler interface. Responsibility of this class is to add JSON payload containing JWT Access and Refresh tokens into the HTTP response body.
@Component public class AjaxAwareAuthenticationSuccessHandler implements AuthenticationSuccessHandler { private final ObjectMapper mapper; private final JwtTokenFactory tokenFactory; @Autowired public AjaxAwareAuthenticationSuccessHandler(final ObjectMapper mapper, final JwtTokenFactory tokenFactory) { this.mapper = mapper; this.tokenFactory = tokenFactory; } @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { UserContext userContext = (UserContext) authentication.getPrincipal(); JwtToken accessToken = tokenFactory.createAccessJwtToken(userContext); JwtToken refreshToken = tokenFactory.createRefreshToken(userContext); Map<String, String> tokenMap = new HashMap<String, String>(); tokenMap.put("token", accessToken.getToken()); tokenMap.put("refreshToken", refreshToken.getToken()); response.setStatus(HttpStatus.OK.value()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); mapper.writeValue(response.getWriter(), tokenMap); clearAuthenticationAttributes(request); } /** * Removes temporary authentication-related data which may have been stored * in the session during the authentication process.. * */ protected final void clearAuthenticationAttributes(HttpServletRequest request) { HttpSession session = request.getSession(false); if (session == null) { return; } session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION); } }Let's focus for a moment on how JWT Access token is created. In this tutorial we are using?Java JWT?library created by?Stormpath.
Make sure that?JJWT?dependency is included in your?pom.xml.
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jjwt.version}</version> </dependency>We have created factory class (JwtTokenFactory) to decouple token creation logic.
Method?JwtTokenFactory#createAccessJwtToken?creates signed JWT Access token.
Method?JwtTokenFactory#createRefreshToken?creates signed JWT Refresh token.
@Component public class JwtTokenFactory { private final JwtSettings settings; @Autowired public JwtTokenFactory(JwtSettings settings) { this.settings = settings; } /** * Factory method for issuing new JWT Tokens. * * @param username * @param roles * @return */ public AccessJwtToken createAccessJwtToken(UserContext userContext) { if (StringUtils.isBlank(userContext.getUsername())) throw new IllegalArgumentException("Cannot create JWT Token without username"); if (userContext.getAuthorities() == null || userContext.getAuthorities().isEmpty()) throw new IllegalArgumentException("User doesn't have any privileges"); Claims claims = Jwts.claims().setSubject(userContext.getUsername()); claims.put("scopes", userContext.getAuthorities().stream().map(s -> s.toString()).collect(Collectors.toList())); DateTime currentTime = new DateTime(); String token = Jwts.builder() .setClaims(claims) .setIssuer(settings.getTokenIssuer()) .setIssuedAt(currentTime.toDate()) .setExpiration(currentTime.plusMinutes(settings.getTokenExpirationTime()).toDate()) .signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey()) .compact(); return new AccessJwtToken(token, claims); } public JwtToken createRefreshToken(UserContext userContext) { if (StringUtils.isBlank(userContext.getUsername())) { throw new IllegalArgumentException("Cannot create JWT Token without username"); } DateTime currentTime = new DateTime(); Claims claims = Jwts.claims().setSubject(userContext.getUsername()); claims.put("scopes", Arrays.asList(Scopes.REFRESH_TOKEN.authority())); String token = Jwts.builder() .轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/6496392.html
總結(jié)
以上是生活随笔為你收集整理的JWT Authentication Tutorial: An example using Spring Boot--转的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 是时候抛弃web.xml了?
- 下一篇: Spring Security Arch