JWT (JSON Web Token) es un estándar abierto basado en JSON (RFC 7519) implementado para aprobar reclamos entre entornos de aplicación de red. El token está diseñado para ser compacto y seguro, especialmente adecuado para escenarios de inicio de sesión único (SSO) de sitios distribuidos. La declaración JWT generalmente se utiliza para aprobar información de identidad de usuario autenticada entre proveedores de identidad y proveedores de servicios para facilitar la adquisición de recursos del servidor de recursos. También puede agregar alguna información de declaración adicional necesaria para otra lógica comercial. El token también se puede usar directamente para la autenticación o en cifrado.
Por lo general, es muy arriesgado exponer la API directamente. Si no habla de nada más, puede beberlo si es atacado directamente por una máquina. En términos generales, un cierto nivel de permiso debe dividirse en la API, y luego se realiza una autenticación del usuario, y la API correspondiente se da al usuario en función de los resultados de la autenticación. En la actualidad, hay varias soluciones más convencionales:
OAuth es un estándar de autorización abierto que permite a los usuarios permitir que las aplicaciones de terceros accedan a recursos privados (como fotos, videos) almacenados por el usuario en un servicio sin proporcionar nombre de usuario y contraseña a aplicaciones de terceros.
OAuth permite a los usuarios proporcionar un token en lugar de un nombre de usuario y una contraseña para acceder a los datos que almacenan en un proveedor de servicios específico. Cada token autoriza un sistema específico de terceros (por ejemplo, un sitio web de edición de video) para acceder a un recurso específico (por ejemplo, solo un video en un determinado álbum) dentro de un período de tiempo específico (por ejemplo, dentro de las próximas 2 horas). De esta manera, OAuth permite a los usuarios autorizar sitios web de terceros para acceder a cierta información específica que almacenan en otros proveedores de servicios, en lugar de todo el contenido.
El mecanismo de autenticación de cookies es crear un objeto de sesión en el servidor para una solicitud de autenticación y, al mismo tiempo, crear un objeto de cookie en el navegador del cliente; El objeto de cookie se lleva al cliente para que coincida con el objeto de sesión en el servidor para lograr la administración de estado. Por defecto, las cookies se eliminarán cuando cerremos el navegador. Sin embargo, puede modificar el tiempo de caducidad de la cookie para hacer que la cookie sea válida por un cierto período de tiempo. La autenticación basada en el método de sesión inevitablemente ejercerá cierta presión sobre el servidor (almacenamiento de memoria), no es fácil de expandir (que requiere manejar sesiones distribuidas), ataques de falsificación de solicitudes de sitios cruzados (CSRF)
1. En comparación con la sesión, no es necesario guardarlo en el servidor y no ocupa la sobrecarga de memoria del servidor.
2. Sin estado y altamente escalable: por ejemplo, hay 3 máquinas (A, B, C) para formar un clúster de servidor. Si la sesión existe en la máquina A, la sesión solo se puede guardar en uno de los servidores. En este momento, no puede acceder a las máquinas B y C, porque la sesión no se almacena en B y C, y el uso de tokens puede verificar la legitimidad de la solicitud del usuario. Está bien que agregue algunas máquinas más, así que esto es lo que significa.
3. Separación frontal y soporte de acceso al dominio cruzado.
- La composición de JWT
{"ISS": "JWT Builder", "IAT": 1416797419, "Exp": 14483333419, "aud": "www.battcn.com", "sub": "[email protected]", "dada": "levin", "nochi "[email protected]", "rol": ["admin", "miembro"]}Un JWT es en realidad una cadena, que consta de tres partes, encabezado, carga útil y firma (ordenada en secuencia en la imagen de arriba)
Generador de token JWT: https://jwt.io/
- Iniciar sesión autenticación
- Solicitud de autenticación
Token inválido
Token válido
Hay ventajas y desventajas. Si es aplicable debe considerarse claramente, en lugar de la tecnología y el estilo.
TokenProperties Mapeo de clave con Application.yml Resource, fácil de usar
@Configuration@ConfigurationProperties (prefix = "Battcn.security.token") public class tokenProperties { / *** {@link com.battcn.security.model.token.token} token time* / private intreger expirationtime; / *** Emisor*/ Emisor de cadena privada; /*** La firma usó la clave {@link com.battcn.security.model.token.token}. */ string private string firmingkey; / *** {@link com.battcn.security.model.token.token} renovar tiempo de vencimiento*/ privado entero refreshExpTime; // Ponte configurado ...} Clase generada por token
@ComponentPublic Class TokenFactory {Propiedades finales de TokenProperties finales privadas; @AUtowired public tokenFactory (TokenProperties Properties) {this.properties = Properties; } / ** * use jjwt para generar token * @param context * @return * / public accesstoken createAccessToken (context de oso y contexto) {opcional.ofnullable (context.getUsername ()). Orelsethrow (()-> nuevo ilegalargumentException ("no puede crear token sin nombre")); Opcional.ofnullable (context.getAuthorities ()). Orelsethrow (()-> new IlegalArGumentException ("El usuario no tiene ningún privilegio")); Reclamos reclamos = jwts.claims (). SetSubject (context.getUsername ()); reclame.put ("Scopes", context.getAuthorities (). Stream (). MAP (Object :: ToString) .Collect (tolist ())); LocalDateTime CurrentTime = localDateTime.Now (); String token = jwts.builder () .setClaims (reclamos) .setissuer (propiedades.getissuer ()) .setisSueDAT (date.from (currentTime.atzone (zoneID.systemDefault ()). ToInstant ())) .setExpiration (date.from (currusTime.plusmines (propiedades.getExpirationtimation ())) .atzone (ZoneId.SystemDefault ()). ToInstant ())) .signwith (SignATreaRealGorithM.HS512, Properties.getSigningKey ()) .Compact (); devolver nuevo AccessToken (token, reclamos); } / ** * Genere y actualice RefreshToken * @param Usercontext * @return * / public token CreateReFreshToken (UserContext UserContext) {if (StringUtils.isblank (UserContext.getUsername ()))) {tirar nueva ilegalargumentException ("No puede crear token sin nombre"); } LocalDateTime CurrentTime = localDateTime.Now (); Reclamos reclamos = jwts.claims (). SetSubject (Usercontext.getUsername ()); reclame.put ("Scopes", Arrays.aslist (Scopes.Refresh_Token.Authority ())); String token = jwts.builder () .setClaims (reclamos) .setissuer (propiedades.getissuer ()) .setId (uuid.randomuuiD (). ToString ()) .setissueDat (date.from (currentTime.atzone (zoneId.Systemdefault ().). Toinstant ())). .PlusMinutes (Properties.getRefreshexpTime ())) .atzone (ZoneId.SystemDefault ()). ToInstant ())) .signwith (SignAtreaalGorithm.hs512, Properties.getSigningKey ()) .Compact (); devolver nuevo AccessToken (token, reclamos); }} El archivo de configuración, incluido el tiempo de vencimiento del token, la clave secreta, se puede ampliar solo
Battcn: Seguridad: Token: Tiempo de vencimiento: 10 # minutos 1440 RECRESH-Exp-Exp-tim-timá
WebSecurityConfig es una configuración clave de Spring Security. En seguridad, básicamente podemos implementar las funciones que queremos definiendo filtros.
@Configuration@enablewebsecuritypublic publicidad WebSecurityConfig extiende WebSecurityConfigurerAdapter {public static final String token_header_param = "X-Authorization"; Cadena final Public Static Form_based_login_entry_point = "/api/auth/login"; public static final String token_based_auth_entry_point = "/api/**"; Public static final String management_token_based_auth_entry_point = "/management/**"; public static final String token_refresh_entry_point = "/api/auth/token"; @AUTOWIREDIRDEDREDEDREDETACIÓN PRIVADA AUTENTACIÓN AUTENTACIÓN DE AUTENTACIÓN @AUTOWIREDIRIRD AuthenticationSuccessHandler SuccessHandler; @AUTOWIREDIRIRD AuthenticationFailureHandler FailsHandler; @AUTOWIREDIRDIRD LoginauthenticationProvider LoginauthenticationProvider; @Autowired Private TokenauthenticationProvider TokenauthenticationProvider; @Autowired Private Tokenextractor Tokenextractor; @AUTOWIRED AuthenticationManager de autenticación de autenticación; LoginProcessingFilter protegido BuildLoginProcessingFilter () lanza la excepción {LoginProcessingFilter Filter = new LogInProcessingFilter (Form_based_login_entry_point, SuccessHandler, FailsHandler); filter.setAuthenticationManager (this.authenticationManager); Filtro de retorno; } Tokenauthentication ProtectedProcessingFilter BuildTokenAuthenticationProcessingFilter () lanza la excepción {list <string> list = lists.newarrayList (token_based_auth_entry_point, manage_token_based_auth_entry_point); SkippathRequestMatcher Matcher = new SkippathRequestMatcher (lista); TokenauthenticationProcessingFilter Filter = new TokenauthenticationProcessingFilter (FailsHandler, Tokenextractor, Matcher); filter.setAuthenticationManager (this.authenticationManager); Filtro de retorno; } @Bean @Override public AuthenticationManager AuthenticationManagerBean () lanza excepción {return super.authenticationManagerBean (); } @Override Protected Void Configurar (AuthenticationManagerBuilder Auth) {Auth.AuthenticationProvider (loginauthenticationProvider); auth.authenticationProvider (TokenauthenticationProvider); } @Override Proteged void configure (httpsecurity http) lanza la excepción {http .csrf (). Disable () // porque está usando jwt, puede desactivar csrf aquí.exceptionHandling () .authenticationEntryPoint (this.AuthenticationRyPoint) .and () .sessionManAsion () .SessionCreationPolicy (sessionCreationPolicy.stateless) .and () .authorizeRequests () .antmatchers (form_based_login_entry_point) .permitall () // login-punta final .antmatchers (token_refresh_entry_point) .permitall () // token-pointen-pooint .and () () .authorizequests () .antMatchers (token_based_auth_entry_point) .authenticated () // Points finales de API protegidos .antMatchers (manage_token_based_auth_entry_point) .hasanyrole (roleenum.admin.name ().). .addfilterbefore (buildLogInProcessingFilter (), usernamePassWalDauthenticationFilter.class) .addfilterbefore (buildTokenAuthenticationProcessingFilter (), usernamePasswordAuthenticationFilter.class); }}Dado que el código JWT simplemente está encapsulado y contiene mucho contenido, solo los fragmentos principales se publican en el artículo. Si se necesita el código completo, puede obtenerlo directamente del siguiente git
Código de este capítulo (battcn-jwt-service): http://xiazai.vevb.com/201801/yuanma/battcncloud_jb51.rar
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.