Selaa lähdekoodia

JWT独立子项目

Crystal.Sea 4 vuotta sitten
vanhempi
commit
a526e7a596
24 muutettua tiedostoa jossa 903 lisäystä ja 35 poistoa
  1. 2 0
      maxkey-core/src/main/java/org/maxkey/constants/ConstantsProtocols.java
  2. 159 0
      maxkey-core/src/main/java/org/maxkey/domain/apps/AppsJwtDetails.java
  3. 33 0
      maxkey-persistence/src/main/java/org/maxkey/persistence/mapper/AppsJwtDetailsMapper.java
  4. 44 0
      maxkey-persistence/src/main/java/org/maxkey/persistence/service/AppsJwtDetailsService.java
  5. 18 0
      maxkey-persistence/src/main/resources/org/maxkey/persistence/mapper/xml/mysql/AppsJwtDetailsMapper.xml
  6. 3 10
      maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/endpoint/AuthorizeEndpoint.java
  7. 13 0
      maxkey-protocols/maxkey-protocol-jwt/build.gradle
  8. 3 0
      maxkey-protocols/maxkey-protocol-jwt/src/main/java/META-INF/MANIFEST.MF
  9. 7 7
      maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtAdapter.java
  10. 114 0
      maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtDefaultAdapter.java
  11. 7 7
      maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtHS256Adapter.java
  12. 140 0
      maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/token/endpoint/JwtAuthorizeEndpoint.java
  13. 125 0
      maxkey-web-manage/src/main/java/org/maxkey/web/apps/contorller/JwtDetailsController.java
  14. 1 1
      maxkey-web-manage/src/main/resources/application.properties
  15. 10 0
      maxkey-web-manage/src/main/resources/messages/message.properties
  16. 10 0
      maxkey-web-manage/src/main/resources/messages/message_en.properties
  17. 11 0
      maxkey-web-manage/src/main/resources/messages/message_zh_CN.properties
  18. 6 4
      maxkey-web-manage/src/main/resources/templates/views/apps/appsList.ftl
  19. 95 0
      maxkey-web-manage/src/main/resources/templates/views/apps/jwt/appAdd.ftl
  20. 95 0
      maxkey-web-manage/src/main/resources/templates/views/apps/jwt/appUpdate.ftl
  21. 1 1
      maxkey-web-maxkey/build.gradle
  22. 1 1
      maxkey-web-maxkey/src/main/resources/application.properties
  23. 0 0
      maxkey-web-maxkey/src/main/resources/templates/views/authorize/jwt_sso_submint.ftl
  24. 5 4
      settings.gradle

+ 2 - 0
maxkey-core/src/main/java/org/maxkey/constants/ConstantsProtocols.java

@@ -42,5 +42,7 @@ public final class ConstantsProtocols {
     public static final String OPEN_ID_CONNECT = "OpenID_Connect";
 
     public static final String CAS = "CAS";
+    
+    public static final String JWT = "JWT";
 
 }

+ 159 - 0
maxkey-core/src/main/java/org/maxkey/domain/apps/AppsJwtDetails.java

@@ -0,0 +1,159 @@
+/*
+ * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+
+/**
+ * 
+ */
+package org.maxkey.domain.apps;
+
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+/**
+ * @author Crystal.Sea
+ *
+ */
+@Table(name = "MXK_APPS_JWT_DETAILS") 
+public class AppsJwtDetails  extends Apps {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -1717427271305620545L;
+
+	@Id
+	@Column
+	@GeneratedValue(strategy=GenerationType.AUTO,generator="uuid")
+	protected String id;
+	/**
+	 * 
+	 */
+	@Column
+	private String redirectUri;
+	//
+	@Column
+	private String tokenType;
+	@Column
+	private String cookieName;
+	@Column
+	private String algorithm;
+	@Column
+	private String algorithmKey;
+	@Column
+	private String expires;
+		
+	
+	public AppsJwtDetails() {
+		super();
+	}
+
+
+    public String getId() {
+        return id;
+    }
+
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+
+    public String getRedirectUri() {
+        return redirectUri;
+    }
+
+
+    public void setRedirectUri(String redirectUri) {
+        this.redirectUri = redirectUri;
+    }
+
+
+    public String getTokenType() {
+        return tokenType;
+    }
+
+
+    public void setTokenType(String tokenType) {
+        this.tokenType = tokenType;
+    }
+
+
+    public String getCookieName() {
+        return cookieName;
+    }
+
+
+    public void setCookieName(String cookieName) {
+        this.cookieName = cookieName;
+    }
+
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+
+    public String getAlgorithmKey() {
+        return algorithmKey;
+    }
+
+
+    public void setAlgorithmKey(String algorithmKey) {
+        this.algorithmKey = algorithmKey;
+    }
+
+
+    public String getExpires() {
+        return expires;
+    }
+
+
+    public void setExpires(String expires) {
+        this.expires = expires;
+    }
+
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("AppsTokenBasedDetails [id=");
+        builder.append(id);
+        builder.append(", redirectUri=");
+        builder.append(redirectUri);
+        builder.append(", tokenType=");
+        builder.append(tokenType);
+        builder.append(", cookieName=");
+        builder.append(cookieName);
+        builder.append(", algorithm=");
+        builder.append(algorithm);
+        builder.append(", algorithmKey=");
+        builder.append(algorithmKey);
+        builder.append(", expires=");
+        builder.append(expires);
+        builder.append("]");
+        return builder.toString();
+    }
+
+}

+ 33 - 0
maxkey-persistence/src/main/java/org/maxkey/persistence/mapper/AppsJwtDetailsMapper.java

@@ -0,0 +1,33 @@
+/*
+ * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+
+/**
+ * 
+ */
+package org.maxkey.persistence.mapper;
+
+import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
+import org.maxkey.domain.apps.AppsJwtDetails;
+
+/**
+ * @author Crystal.sea
+ *
+ */
+public  interface AppsJwtDetailsMapper extends IJpaBaseMapper<AppsJwtDetails> {
+	
+	public  AppsJwtDetails  getAppDetails(String id);
+}

+ 44 - 0
maxkey-persistence/src/main/java/org/maxkey/persistence/service/AppsJwtDetailsService.java

@@ -0,0 +1,44 @@
+/*
+ * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+
+package org.maxkey.persistence.service;
+
+import org.apache.mybatis.jpa.persistence.JpaBaseService;
+import org.maxkey.domain.apps.AppsJwtDetails;
+import org.maxkey.persistence.mapper.AppsJwtDetailsMapper;
+import org.springframework.stereotype.Service;
+
+@Service
+public class AppsJwtDetailsService  extends JpaBaseService<AppsJwtDetails>{
+
+	public AppsJwtDetailsService() {
+		super(AppsJwtDetailsMapper.class);
+	}
+
+	/* (non-Javadoc)
+	 * @see com.connsec.db.service.BaseService#getMapper()
+	 */
+	@Override
+	public AppsJwtDetailsMapper getMapper() {
+		// TODO Auto-generated method stub
+		return (AppsJwtDetailsMapper)super.getMapper();
+	}
+	
+	public  AppsJwtDetails  getAppDetails(String id) {
+		return getMapper().getAppDetails(id);
+	}
+}

+ 18 - 0
maxkey-persistence/src/main/resources/org/maxkey/persistence/mapper/xml/mysql/AppsJwtDetailsMapper.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.maxkey.persistence.mapper.AppsJwtDetailsMapper">
+
+<select id="getAppDetails" parameterType="string" resultType="AppsJwtDetails">
+    	SELECT 
+			*
+    	FROM 
+    		MXK_APPS_JWT_DETAILS JD,
+    		MXK_APPS APP
+    	WHERE 	
+    		APP.ID	=	#{value}
+    		AND JD.ID	=	#{value}
+    		AND JD.ID	=	APP.ID
+    		AND STATUS	=	1
+    </select>
+	
+</mapper>

+ 3 - 10
maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/endpoint/AuthorizeEndpoint.java

@@ -68,7 +68,9 @@ public class AuthorizeEndpoint extends AuthorizeBaseEndpoint{
 			modelAndView=WebContext.forward("/authz/tokenbased/"+id);
 		}else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.CAS)){
 			modelAndView=WebContext.forward("/authz/cas/"+id);
-		}else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.DESKTOP)){
+		}else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.JWT)){
+            modelAndView=WebContext.forward("/authz/jwt/"+id);
+        }else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.DESKTOP)){
 			modelAndView=WebContext.forward("/authz/desktop/"+id);
 		}else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.BASIC)){
 			modelAndView=WebContext.redirect(application.getLoginUrl());
@@ -78,14 +80,5 @@ public class AuthorizeEndpoint extends AuthorizeBaseEndpoint{
 		
 		return modelAndView;
 	}
-
-	@RequestMapping("/authz/oauth10a/{id}")
-	public ModelAndView authorizeOAuth10a(
-			@PathVariable("id") String id){
-		
-		 String redirec_uri=getApp(id).getLoginUrl();
-		return WebContext.redirect(redirec_uri);
-		
-	}
 	
 }

+ 13 - 0
maxkey-protocols/maxkey-protocol-jwt/build.gradle

@@ -0,0 +1,13 @@
+
+description = "maxkey-protocol-jwt"
+
+
+dependencies {
+	//local jars
+	compile fileTree(dir: '../maxkey-lib/*/', include: '*.jar')
+	
+	compile project(":maxkey-core")
+	compile project(":maxkey-persistence")
+   	compile project(":maxkey-protocols:maxkey-protocol-authorize")
+   
+}

+ 3 - 0
maxkey-protocols/maxkey-protocol-jwt/src/main/java/META-INF/MANIFEST.MF

@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: 
+

+ 7 - 7
maxkey-protocols/maxkey-protocol-tokenbased/src/main/java/org/maxkey/authz/token/endpoint/adapter/TokenBasedJWTAdapter.java → maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtAdapter.java

@@ -15,7 +15,7 @@
  */
  
 
-package org.maxkey.authz.token.endpoint.adapter;
+package org.maxkey.authz.jwt.endpoint.adapter;
 
 import java.util.Arrays;
 import java.util.Date;
@@ -28,7 +28,7 @@ import org.maxkey.configuration.oidc.OIDCProviderMetadata;
 import org.maxkey.crypto.jwt.signer.service.JwtSigningAndValidationService;
 import org.maxkey.domain.UserInfo;
 import org.maxkey.domain.apps.Apps;
-import org.maxkey.domain.apps.AppsTokenBasedDetails;
+import org.maxkey.domain.apps.AppsJwtDetails;
 import org.maxkey.web.WebConstants;
 import org.maxkey.web.WebContext;
 import org.slf4j.Logger;
@@ -42,11 +42,11 @@ import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.PlainJWT;
 import com.nimbusds.jwt.SignedJWT;
 
-public class TokenBasedJWTAdapter extends AbstractAuthorizeAdapter {
-	final static Logger _logger = LoggerFactory.getLogger(TokenBasedJWTAdapter.class);
+public class JwtAdapter extends AbstractAuthorizeAdapter {
+	final static Logger _logger = LoggerFactory.getLogger(JwtAdapter.class);
 	@Override
 	public String generateInfo(SigninPrincipal authentication,UserInfo userInfo,Object app) {
-		AppsTokenBasedDetails details=(AppsTokenBasedDetails)app;
+		AppsJwtDetails details=(AppsJwtDetails)app;
 	
 		
 		JwtSigningAndValidationService jwtSignerService= (JwtSigningAndValidationService)WebContext.getBean("jwtSignerValidationService");
@@ -111,8 +111,8 @@ public class TokenBasedJWTAdapter extends AbstractAuthorizeAdapter {
 
 	@Override
 	public ModelAndView authorize(UserInfo userInfo, Object app, String data,ModelAndView modelAndView) {
-		modelAndView.setViewName("authorize/tokenbased_jwt_sso_submint");
-		AppsTokenBasedDetails details=(AppsTokenBasedDetails)app;
+		modelAndView.setViewName("authorize/jwt_sso_submint");
+		AppsJwtDetails details=(AppsJwtDetails)app;
 		modelAndView.addObject("action", details.getRedirectUri());
 		_logger.debug("jwt Token data : "+data);
 		

+ 114 - 0
maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtDefaultAdapter.java

@@ -0,0 +1,114 @@
+/*
+ * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+
+package org.maxkey.authz.jwt.endpoint.adapter;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.maxkey.authn.SigninPrincipal;
+import org.maxkey.authz.endpoint.adapter.AbstractAuthorizeAdapter;
+import org.maxkey.configuration.oidc.OIDCProviderMetadata;
+import org.maxkey.crypto.jwt.signer.service.JwtSigningAndValidationService;
+import org.maxkey.domain.UserInfo;
+import org.maxkey.domain.apps.AppsJwtDetails;
+import org.maxkey.web.WebConstants;
+import org.maxkey.web.WebContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jwt.JWT;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.PlainJWT;
+import com.nimbusds.jwt.SignedJWT;
+
+public class JwtDefaultAdapter extends AbstractAuthorizeAdapter {
+	final static Logger _logger = LoggerFactory.getLogger(JwtDefaultAdapter.class);
+	@Override
+	public String generateInfo(SigninPrincipal authentication,UserInfo userInfo,Object app) {
+	    AppsJwtDetails details=(AppsJwtDetails)app;
+    
+        
+        JwtSigningAndValidationService jwtSignerService= (JwtSigningAndValidationService)WebContext.getBean("jwtSignerValidationService");
+        OIDCProviderMetadata providerMetadata= (OIDCProviderMetadata)WebContext.getBean("oidcProviderMetadata");
+    
+        DateTime currentDateTime=DateTime.now();
+        
+        Date expirationTime=currentDateTime.plusMinutes(Integer.parseInt(details.getExpires())).toDate();
+        _logger.debug("expiration Time : "+expirationTime);
+        
+        JWTClaimsSet jwtClaims =new  JWTClaimsSet.Builder()
+                .issuer(providerMetadata.getIssuer())
+                .subject(userInfo.getUsername())
+                .audience(Arrays.asList(details.getId()))
+                .jwtID(UUID.randomUUID().toString())
+                .issueTime(currentDateTime.toDate())
+                .expirationTime(expirationTime)
+                .claim("email", userInfo.getWorkEmail())
+                .claim("name", userInfo.getUsername())
+                .claim("user_id", userInfo.getId())
+                .claim("external_id", userInfo.getId())
+                .claim("locale", userInfo.getLocale())
+                .claim(WebConstants.ONLINE_TICKET_NAME, authentication.getOnlineTicket().getTicketId())
+                .claim("kid", jwtSignerService.getDefaultSignerKeyId())
+                .build();
+        
+        _logger.debug("jwt Claims : "+jwtClaims);
+        
+        JWT jwtToken = new PlainJWT(jwtClaims);
+        
+        JWSAlgorithm signingAlg = jwtSignerService.getDefaultSigningAlgorithm();
+        
+        //get PublicKey
+        /*Map<String, JWK>  jwkMap=jwtSignerService.getAllPublicKeys();
+        
+        JWK jwk=jwkMap.get("connsec_rsa1");
+        
+        _logger.debug("isPrivate "+jwk.isPrivate());*/
+        
+        _logger.debug(" signingAlg "+signingAlg);
+        
+        jwtToken = new SignedJWT(new JWSHeader(signingAlg), jwtClaims);
+        // sign it with the server's key
+        jwtSignerService.signJwt((SignedJWT) jwtToken);
+        
+        String tokenString=jwtToken.serialize();
+        _logger.debug("jwt Token : "+tokenString);
+        
+        return tokenString;
+	}
+
+	@Override
+	public String encrypt(String data, String algorithmKey, String algorithm) {
+		return super.encrypt(data, algorithmKey, algorithm);
+	}
+
+	@Override
+	public ModelAndView authorize(UserInfo userInfo, Object app, String data,ModelAndView modelAndView) {
+		modelAndView.setViewName("authorize/jwt_sso_submint");
+		AppsJwtDetails details=(AppsJwtDetails)app;
+		modelAndView.addObject("action", details.getRedirectUri());
+		
+		modelAndView.addObject("token",data );
+		return modelAndView;
+	}
+}

+ 7 - 7
maxkey-protocols/maxkey-protocol-tokenbased/src/main/java/org/maxkey/authz/token/endpoint/adapter/TokenBasedJWTHS256Adapter.java → maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtHS256Adapter.java

@@ -15,7 +15,7 @@
  */
  
 
-package org.maxkey.authz.token.endpoint.adapter;
+package org.maxkey.authz.jwt.endpoint.adapter;
 
 import java.util.Arrays;
 import java.util.Date;
@@ -30,7 +30,7 @@ import org.maxkey.crypto.jwt.signer.service.JwtSigningAndValidationService;
 import org.maxkey.crypto.jwt.signer.service.impl.SymmetricSigningAndValidationServiceBuilder;
 import org.maxkey.domain.UserInfo;
 import org.maxkey.domain.apps.Apps;
-import org.maxkey.domain.apps.AppsTokenBasedDetails;
+import org.maxkey.domain.apps.AppsJwtDetails;
 import org.maxkey.web.WebConstants;
 import org.maxkey.web.WebContext;
 import org.slf4j.Logger;
@@ -44,13 +44,13 @@ import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.PlainJWT;
 import com.nimbusds.jwt.SignedJWT;
 
-public class TokenBasedJWTHS256Adapter extends AbstractAuthorizeAdapter {
-	final static Logger _logger = LoggerFactory.getLogger(TokenBasedJWTHS256Adapter.class);
+public class JwtHS256Adapter extends AbstractAuthorizeAdapter {
+	final static Logger _logger = LoggerFactory.getLogger(JwtHS256Adapter.class);
 	private SymmetricSigningAndValidationServiceBuilder symmetricJwtSignerServiceBuilder=new SymmetricSigningAndValidationServiceBuilder();
 
 	@Override
 	public String generateInfo(SigninPrincipal authentication,UserInfo userInfo,Object app) {
-		AppsTokenBasedDetails details=(AppsTokenBasedDetails)app;
+		AppsJwtDetails details=(AppsJwtDetails)app;
 		
 		OIDCProviderMetadata providerMetadata= (OIDCProviderMetadata)WebContext.getBean("oidcProviderMetadata");
 	
@@ -108,8 +108,8 @@ public class TokenBasedJWTHS256Adapter extends AbstractAuthorizeAdapter {
 
 	@Override
 	public ModelAndView authorize(UserInfo userInfo, Object app, String data,ModelAndView modelAndView) {
-		modelAndView.setViewName("authorize/tokenbased_jwt_sso_submint");
-		AppsTokenBasedDetails details=(AppsTokenBasedDetails)app;
+		modelAndView.setViewName("authorize/jwt_sso_submint");
+		AppsJwtDetails details=(AppsJwtDetails)app;
 		modelAndView.addObject("action", details.getRedirectUri());
 		_logger.debug("jwt Token data : "+data);
 		

+ 140 - 0
maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/token/endpoint/JwtAuthorizeEndpoint.java

@@ -0,0 +1,140 @@
+/*
+ * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+
+/**
+ * 
+ */
+package org.maxkey.authz.token.endpoint;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.maxkey.authn.SigninPrincipal;
+import org.maxkey.authz.endpoint.AuthorizeBaseEndpoint;
+import org.maxkey.authz.endpoint.adapter.AbstractAuthorizeAdapter;
+import org.maxkey.authz.jwt.endpoint.adapter.JwtDefaultAdapter;
+import org.maxkey.configuration.ApplicationConfig;
+import org.maxkey.constants.Boolean;
+import org.maxkey.domain.apps.Apps;
+import org.maxkey.domain.apps.AppsJwtDetails;
+import org.maxkey.persistence.service.AppsJwtDetailsService;
+import org.maxkey.util.Instance;
+import org.maxkey.web.WebContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * @author Crystal.Sea
+ *
+ */
+@Controller
+public class JwtAuthorizeEndpoint  extends AuthorizeBaseEndpoint{
+
+	final static Logger _logger = LoggerFactory.getLogger(JwtAuthorizeEndpoint.class);
+	
+	@Autowired
+	AppsJwtDetailsService jwtDetailsService;
+	
+	JwtDefaultAdapter jwtDefaultAdapter=new JwtDefaultAdapter();
+	
+	@Autowired
+	ApplicationConfig applicationConfig;
+	
+	@RequestMapping("/authz/jwt/{id}")
+	public ModelAndView authorize(
+			HttpServletRequest request,
+			HttpServletResponse response,
+			@PathVariable("id") String id){
+		ModelAndView modelAndView=new ModelAndView();
+		
+		
+		AppsJwtDetails jwtDetails=null;
+		jwtDetails=jwtDetailsService.getAppDetails(id);
+		_logger.debug(""+jwtDetails);
+		
+		Apps  application= getApp(id);
+		jwtDetails.setAdapter(application.getAdapter());
+		jwtDetails.setIsAdapter(application.getIsAdapter());
+		
+		AbstractAuthorizeAdapter adapter;
+		if(Boolean.isTrue(jwtDetails.getIsAdapter())){
+			adapter =(AbstractAuthorizeAdapter)Instance.newInstance(jwtDetails.getAdapter());
+		}else{
+			adapter =(AbstractAuthorizeAdapter)jwtDefaultAdapter;
+		}
+		
+		String tokenData=adapter.generateInfo(
+		        (SigninPrincipal)WebContext.getAuthentication().getPrincipal(),
+				WebContext.getUserInfo(), 
+				jwtDetails);
+		
+		String encryptTokenData=adapter.encrypt(
+				tokenData, 
+				jwtDetails.getAlgorithmKey(), 
+				jwtDetails.getAlgorithm());
+		
+		String signTokenData=adapter.sign(
+				encryptTokenData, 
+				jwtDetails);
+		
+		if(jwtDetails.getTokenType().equalsIgnoreCase("POST")) {
+			modelAndView=adapter.authorize(
+					WebContext.getUserInfo(), 
+					jwtDetails, 
+					signTokenData, 
+					modelAndView);
+			
+			return modelAndView;
+		}else {
+			
+			String cookieValue="";
+			cookieValue=signTokenData;
+			
+			_logger.debug("Cookie Name : "+jwtDetails.getCookieName());
+			
+			Cookie cookie= new Cookie(jwtDetails.getCookieName(),cookieValue);
+			
+			Integer maxAge=Integer.parseInt(jwtDetails.getExpires())*60;
+			_logger.debug("Cookie Max Age :"+maxAge+" seconds.");
+			cookie.setMaxAge(maxAge);
+			
+			cookie.setPath("/");
+			//
+			//cookie.setDomain("."+applicationConfig.getBaseDomainName());
+			//tomcat 8.5
+			cookie.setDomain(applicationConfig.getBaseDomainName());
+			
+			_logger.debug("Sub Domain Name : "+"."+applicationConfig.getBaseDomainName());
+			response.addCookie(cookie);
+			
+			if(jwtDetails.getRedirectUri().indexOf(applicationConfig.getBaseDomainName())>-1){
+				return WebContext.redirect(jwtDetails.getRedirectUri());
+			}else{
+				_logger.error(jwtDetails.getRedirectUri()+" not in domain "+applicationConfig.getBaseDomainName());
+				return null;
+			}
+		}
+		
+	}
+
+}

+ 125 - 0
maxkey-web-manage/src/main/java/org/maxkey/web/apps/contorller/JwtDetailsController.java

@@ -0,0 +1,125 @@
+/*
+ * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+
+package org.maxkey.web.apps.contorller;
+
+import org.maxkey.constants.ConstantsOperateMessage;
+import org.maxkey.constants.ConstantsProtocols;
+import org.maxkey.crypto.ReciprocalUtils;
+import org.maxkey.domain.apps.AppsJwtDetails;
+import org.maxkey.persistence.service.AppsJwtDetailsService;
+import org.maxkey.web.WebContext;
+import org.maxkey.web.message.Message;
+import org.maxkey.web.message.MessageType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.servlet.ModelAndView;
+
+
+@Controller
+@RequestMapping(value={"/apps/jwt"})
+public class JwtDetailsController  extends BaseAppContorller {
+	final static Logger _logger = LoggerFactory.getLogger(JwtDetailsController.class);
+	
+	@Autowired
+	AppsJwtDetailsService jwtDetailsService;
+	
+	
+	@RequestMapping(value = { "/forwardAdd" })
+	public ModelAndView forwardAdd() {
+		ModelAndView modelAndView=new ModelAndView("apps/jwt/appAdd");
+		AppsJwtDetails jwtDetails =new AppsJwtDetails();
+		jwtDetails.setId(jwtDetails.generateId());
+		jwtDetails.setProtocol(ConstantsProtocols.JWT);
+		jwtDetails.setSecret(ReciprocalUtils.generateKey(ReciprocalUtils.Algorithm.AES));
+		jwtDetails.setAlgorithmKey(jwtDetails.getSecret());
+		jwtDetails.setUserPropertys("userPropertys");
+		modelAndView.addObject("model",jwtDetails);
+		return modelAndView;
+	}
+	
+	
+	@RequestMapping(value={"/add"})
+	public ModelAndView insert(@ModelAttribute("jwtDetails") AppsJwtDetails jwtDetails) {
+		_logger.debug("-Add  :" + jwtDetails);
+		
+		transform(jwtDetails);
+		
+		jwtDetails.setAlgorithmKey(jwtDetails.getSecret());
+		
+		if (jwtDetailsService.insert(jwtDetails)&&appsService.insertApp(jwtDetails)) {
+			  new Message(WebContext.getI18nValue(ConstantsOperateMessage.INSERT_SUCCESS),MessageType.success);
+			
+		} else {
+			  new Message(WebContext.getI18nValue(ConstantsOperateMessage.INSERT_SUCCESS),MessageType.error);
+		}
+		return   WebContext.forward("forwardUpdate/"+jwtDetails.getId());
+	}
+	
+	@RequestMapping(value = { "/forwardUpdate/{id}" })
+	public ModelAndView forwardUpdate(@PathVariable("id") String id) {
+		ModelAndView modelAndView=new ModelAndView("apps/jwt/appUpdate");
+		AppsJwtDetails jwtDetails=jwtDetailsService.getAppDetails(id);
+		decoderSecret(jwtDetails);
+		String algorithmKey=passwordReciprocal.decoder(jwtDetails.getAlgorithmKey());
+		jwtDetails.setAlgorithmKey(algorithmKey);
+		WebContext.setAttribute(jwtDetails.getId(), jwtDetails.getIcon());
+
+		modelAndView.addObject("model",jwtDetails);
+		return modelAndView;
+	}
+	/**
+	 * modify
+	 * @param application
+	 * @return
+	 */
+	@RequestMapping(value={"/update"})  
+	public ModelAndView update(@ModelAttribute("jwtDetails") AppsJwtDetails jwtDetails) {
+		//
+		_logger.debug("-update  application :" + jwtDetails);
+		transform(jwtDetails);
+		jwtDetails.setAlgorithmKey(jwtDetails.getSecret());
+		if (jwtDetailsService.update(jwtDetails)&&appsService.updateApp(jwtDetails)) {
+			  new Message(WebContext.getI18nValue(ConstantsOperateMessage.UPDATE_SUCCESS),MessageType.success);
+			
+		} else {
+			  new Message(WebContext.getI18nValue(ConstantsOperateMessage.UPDATE_ERROR),MessageType.error);
+		}
+		return   WebContext.forward("forwardUpdate/"+jwtDetails.getId());
+	}
+	
+
+	@ResponseBody
+	@RequestMapping(value={"/delete/{id}"})
+	public Message delete(@PathVariable("id") String id) {
+		_logger.debug("-delete  application :" + id);
+		if (jwtDetailsService.remove(id)&&appsService.remove(id)) {
+			return  new Message(WebContext.getI18nValue(ConstantsOperateMessage.DELETE_SUCCESS),MessageType.success);
+			
+		} else {
+			return  new Message(WebContext.getI18nValue(ConstantsOperateMessage.DELETE_SUCCESS),MessageType.error);
+		}
+	}
+	
+	
+}

+ 1 - 1
maxkey-web-manage/src/main/resources/application.properties

@@ -2,7 +2,7 @@
 #application
 application.title=MaxKey
 application.name=MaxKey-Mgt
-application.formatted-version=v2.3.0 GA
+application.formatted-version=v2.4.0 GA
 #server config
 #server port
 server.port=9521

+ 10 - 0
maxkey-web-manage/src/main/resources/messages/message.properties

@@ -269,6 +269,7 @@ apps.protocol.oauth2.0=OAuth2.0
 apps.protocol.saml2.0=SAML2.0
 apps.protocol.ltpa=\u8f7b\u91cf\u7ea7\u8ba4\u8bc1(LTPA)
 apps.protocol.cas=CAS\u8ba4\u8bc1
+apps.protocol.jwt=JWT\u4ee4\u724c
 apps.protocol.extendapi=API\u6269\u5c55\u8ba4\u8bc1
 apps.protocol.basic=\u57fa\u672c\u767b\u5f55
 apps.vendor=\u4f9b\u5e94\u5546
@@ -339,6 +340,15 @@ apps.tokenbased.algorithm=\u52a0\u5bc6\u7b97\u6cd5
 apps.tokenbased.algorithmKey=\u79d8\u94a5
 apps.tokenbased.token.content=\u4ee4\u724c\u5185\u5bb9
 apps.tokenbased.expires=\u8fc7\u671f\u65f6\u95f4
+#JWT
+apps.jwt.info=JWT\u8ba4\u8bc1
+apps.jwt.redirectUri=\u8ba4\u8bc1\u5730\u5740
+apps.jwt.tokenType=\u4ee4\u724c\u7c7b\u578b
+apps.jwt.cookieName=Cookie\u540d\u79f0
+apps.jwt.algorithm=\u52a0\u5bc6\u7b97\u6cd5
+apps.jwt.algorithmKey=\u79d8\u94a5
+apps.jwt.content=\u4ee4\u724c\u5185\u5bb9
+apps.jwt.expires=\u8fc7\u671f\u65f6\u95f4
 #SAML
 apps.saml.metadata.company=\u516c\u53f8
 apps.saml.spAcsUrl=SP ACS Url

+ 10 - 0
maxkey-web-manage/src/main/resources/messages/message_en.properties

@@ -269,6 +269,7 @@ apps.protocol.oauth2.0=OAuth2.0
 apps.protocol.saml2.0=SAML2.0
 apps.protocol.ltpa=Lightweight Third-Party(LTPA)
 apps.protocol.cas=CAS 
+apps.protocol.jwt=JwtToken
 apps.protocol.extendapi=API Extend
 apps.protocol.basic=Basic
 apps.vendor=vendor
@@ -338,6 +339,15 @@ apps.tokenbased.algorithm=algorithm
 apps.tokenbased.algorithmKey=algorithmKey
 apps.tokenbased.token.content=content
 apps.tokenbased.expires=expires
+#jwt
+apps.jwt.info=JWT Info
+apps.jwt.redirectUri=redirectUri
+apps.jwt.tokenType=tokenType
+apps.jwt.cookieName=Cookie Name
+apps.jwt.algorithm=algorithm
+apps.jwt.algorithmKey=algorithmKey
+apps.jwt.content=content
+apps.jwt.expires=expires
 #SAML
 apps.saml.metadata.company=company
 apps.saml.spAcsUrl=SP ACS Url

+ 11 - 0
maxkey-web-manage/src/main/resources/messages/message_zh_CN.properties

@@ -269,6 +269,7 @@ apps.protocol.oauth2.0=OAuth2.0
 apps.protocol.saml2.0=SAML2.0
 apps.protocol.ltpa=\u8f7b\u91cf\u7ea7\u8ba4\u8bc1(LTPA)
 apps.protocol.cas=CAS\u8ba4\u8bc1
+apps.protocol.jwt=JWT\u4ee4\u724c
 apps.protocol.extendapi=API\u6269\u5c55\u8ba4\u8bc1
 apps.protocol.basic=\u57fa\u672c\u767b\u5f55
 apps.vendor=\u4f9b\u5e94\u5546
@@ -339,6 +340,16 @@ apps.tokenbased.algorithm=\u52a0\u5bc6\u7b97\u6cd5
 apps.tokenbased.algorithmKey=\u79d8\u94a5
 apps.tokenbased.token.content=\u4ee4\u724c\u5185\u5bb9
 apps.tokenbased.expires=\u8fc7\u671f\u65f6\u95f4
+#JWT
+#tokenbased
+apps.jwt.info=JWT\u8ba4\u8bc1
+apps.jwt.redirectUri=\u8ba4\u8bc1\u5730\u5740
+apps.jwt.tokenType=\u4ee4\u724c\u7c7b\u578b
+apps.jwt.cookieName=Cookie\u540d\u79f0
+apps.jwt.algorithm=\u52a0\u5bc6\u7b97\u6cd5
+apps.jwt.algorithmKey=\u79d8\u94a5
+apps.jwt.content=\u4ee4\u724c\u5185\u5bb9
+apps.jwt.expires=\u8fc7\u671f\u65f6\u95f4
 #SAML
 apps.saml.metadata.company=\u516c\u53f8
 apps.saml.spAcsUrl=SP ACS Url

+ 6 - 4
maxkey-web-manage/src/main/resources/templates/views/apps/appsList.ftl

@@ -24,6 +24,7 @@
 	protocolArray["CAS"]="cas";
 	protocolArray["Basic"]="basic";
 	protocolArray["Desktop"]="desktop";
+	protocolArray["JWT"]="jwt";
 	
 	$(function () {
 		$("#modifyApps").on("click",function(){
@@ -131,13 +132,14 @@
 							     	<@locale code="button.text.add"/>
 							  	</button>
 								 <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
-								     <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/formbased/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.formbased" /></a>
-								     <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/desktop/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.desktop" /></a>
-								     <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/tokenbased/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.tokenbased" /></a>
-								     <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/oauth20/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.oauth2.0" /></a>
+								 	 <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/oauth20/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.oauth2.0" /></a>
 								     <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/saml20/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.saml2.0" /></a>
 								     <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/cas/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.cas" /></a>
+								     <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/formbased/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.formbased" /></a>
+								     <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/jwt/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.jwt" /></a>
+								     <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/tokenbased/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.tokenbased" /></a>
 							 		 <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/extendapi/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.extendapi" /></a>
+								     <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/desktop/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.desktop" /></a>
 							 		 <a class="dropdown-item"  target="_blank"  href="<@base/>/apps/basic/forwardAdd">&nbsp;&nbsp;<@locale code="apps.protocol.basic" /></a>
 								  </div>
 							</div>

+ 95 - 0
maxkey-web-manage/src/main/resources/templates/views/apps/jwt/appAdd.ftl

@@ -0,0 +1,95 @@
+<!DOCTYPE HTML>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<#include  "../../layout/header.ftl"/>
+	<#include  "../../layout/common.cssjs.ftl"/>
+	<#include  "../appCommonHead.ftl"/>
+</head>
+<body>
+<form id="actionForm_app"  method="post" type="label" autoclose="true"    closeWindow="true"
+			action="<@base/>/apps/jwt/add"  
+			forward="<@base/>/apps/list"
+			enctype="multipart/form-data"
+			class="needs-validation" novalidate>		 
+  	        <!-- content -->    
+  	      	<!--table-->
+  	      	<table width="960"  class="table table-bordered"  >
+				<tbody>
+				<tr>
+					<td ><#include  "../appAddCommon.ftl"/></td>
+				</tr>
+				<tr>
+					<td>
+						<table width="960"  class="table table-bordered"  >
+						<tbody>
+						<tr>
+							<td colspan=4><@locale code="apps.jwt.info" /></td>
+							</tr>
+							<tr>
+								<th style="width:15%;"><@locale code="apps.jwt.redirectUri" />:</th>
+								<td style="width:35%;" colspan=3>
+									<input type="text" class="form-control" id="redirectUri" name="redirectUri"  title="" value=""  required="" />
+								</td>
+							</tr>
+							<tr>
+									<th ><@locale code="apps.jwt.tokenType" />:</th>
+									<td >
+										<select id="tokenType" name="tokenType"  class="form-control">
+											<option value="POST">安全令牌(TOKEN POST)</option>
+											<option value="LTPA">轻量级认证(LTPA COOKIE)</option>
+										</select>
+									</td>
+									<th ><@locale code="apps.jwt.cookieName" />:</th>
+									<td >
+										<input type="text" class="form-control" id="cookieName" name="cookieName"  title="" value=""/>
+									</td>
+								</tr>
+							<tr>
+								<th style="width:15%;"><@locale code="apps.jwt.algorithm" />:</th>
+								<td style="width:35%;">
+									<select id="algorithm" name="algorithm"   class="form-control">
+										<option value="DES">DES</option>
+										<option value="DESede">DESede</option>
+										<option value="Blowfish">Blowfish</option>
+										<option value="AES"  selected>AES</option>
+										<option value="HS256"  >HMAC SHA-256</option>
+										<option value="RS256"  >RSA SHA-256</option>
+									</select>
+									<b class="orange">*</b><label for="algorithm"></label>
+								</td>
+								<th width="140px"><@locale code="apps.jwt.algorithmKey" />:</th>
+								<td width="340px">
+									<span id="algorithmKey_text">${model.algorithmKey!}</span>
+									<input type="hidden" class="form-control" id="algorithmKey" name="algorithmKey"  title="" value="${model.algorithmKey!}"/>
+								
+								</td>
+							</tr>
+							<tr>
+								<th><@locale code="apps.jwt.content" />:</th>
+								<td>
+									<#include  "../userPropertys.ftl"/>
+								</td>
+								<th><@locale code="apps.jwt.expires" />:</th>
+								<td>
+									<input type="text" class="form-control" id="expires" name="expires"  title="" value="1"  required="" />
+								</td>
+							</tr>
+							<tr>
+								<td colspan =4>
+									<input class="button"  id="status" type="hidden" name="status"  value="1"/>
+						    		<input class="button btn btn-primary mr-3"  id="submitBtn" type="submit" value="<@locale code="button.text.save" />"/>
+									<input class="button btn btn-secondary mr-3"  id="backBtn" type="button" value="<@locale code="button.text.cancel" />"/>		
+								</td>
+							</tr>
+							</tbody>
+						  </table>
+					</td>
+				</tr>
+				</tbody>
+				</table>
+			   
+
+			  
+</form>
+</body>
+</html>

+ 95 - 0
maxkey-web-manage/src/main/resources/templates/views/apps/jwt/appUpdate.ftl

@@ -0,0 +1,95 @@
+<!DOCTYPE HTML>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<#include  "../../layout/header.ftl"/>
+	<#include  "../../layout/common.cssjs.ftl"/>
+	<#include  "../appCommonHead.ftl"/>
+	<#setting number_format="#">
+</head>
+<body>
+<form id="actionForm_app"  method="post" type="label" autoclose="true"   closeWindow="true" 
+			action="<@base/>/apps/jwt/update"  
+			forward="<@base/>/apps/list"
+			enctype="multipart/form-data"
+			class="needs-validation" novalidate>		 
+  	        <!-- content -->    
+  	      	<!--table-->
+  	      	<table width="960"  class="table table-bordered" >
+				<tbody>
+				<tr>
+					<td ><#include  "../appUpdateCommon.ftl"/></td>
+				</tr>
+				<tr>
+					<td>
+				 			<table width="960"   class="table table-bordered" >
+								<tbody>
+								
+								<tr>
+									<td colspan=4><@locale code="apps.jwt.info" /></td>
+								</tr>
+								<tr>
+									<th style="width:15%;"><@locale code="apps.jwt.redirectUri" />:</th>
+									<td  colspan=3>
+										<input type="text" id="redirectUri" class="form-control" name="redirectUri"  title="" value="${model.redirectUri}"  required="" />
+									</td>
+								</tr>
+								<tr>
+									<th ><@locale code="apps.jwt.tokenType" />:</th>
+									<td >
+										<select id="tokenType" name="tokenType"  class="form-control">
+											<option value="POST" <#if 'POST'==model.tokenType>selected</#if> >安全令牌(TOKEN POST)</option>
+											<option value="LTPA" <#if 'LTPA'==model.tokenType>selected</#if> >轻量级认证(LTPA COOKIE)</option>
+										</select>
+									</td>
+									<th ><@locale code="apps.jwt.cookieName" />:</th>
+									<td >
+										<input type="text" class="form-control" id="cookieName" name="cookieName"  title="" value="${model.cookieName!}"/>
+										
+									</td>
+								</tr>
+								<tr>
+									<th style="width:15%;"><@locale code="apps.jwt.algorithm" />:</th>
+									<td style="width:35%;">
+										<select id="algorithm" name="algorithm" class="form-control" >
+											<option value="DES"  <#if 'DES'==model.algorithm>selected</#if> >DES</option>
+											<option value="DESede" <#if 'DESede'==model.algorithm>selected</#if>>DESede</option>
+											<option value="Blowfish" <#if 'Blowfish'==model.algorithm>selected</#if>>Blowfish</option>
+											<option value="AES" <#if 'AES'==model.algorithm>selected</#if>>AES</option>
+											<option value="HS256" <#if 'HS256'==model.algorithm>selected</#if>>HMAC SHA-256</option>
+											<option value="RS256" <#if 'RS256'==model.algorithm>selected</#if>>RSA SHA-256</option>
+											
+										</select>
+									</td>
+									<th style="width:15%;"><@locale code="apps.jwt.algorithmKey" />:</th>
+									<td style="width:35%;">
+										<span id="algorithmKey_text">${model.algorithmKey}</span>
+										<input type="hidden" id="algorithmKey" name="algorithmKey"  title="" value="${model.algorithmKey}"/>
+
+									</td>
+								</tr>
+								<tr>
+									<th><@locale code="apps.jwt.content" />:</th>
+									<td >
+										<#include  "../userPropertys.ftl"/>
+									</td>
+									<th><@locale code="apps.jwt.expires" />:</th>
+									<td>
+										<input type="text" class="form-control" id="expires" name="expires"  title="" value="${model.expires}"  required="" />
+									</td>
+								</tr>
+								
+								<tr>
+									<td colspan =4>
+							    		<input class="button btn btn-primary mr-3"  id="submitBtn" type="submit" value="<@locale code="button.text.save" />"/>
+										<input class="button btn btn-secondary mr-3"  id="backBtn" type="button" value="<@locale code="button.text.cancel" />"/>	
+									</td>
+								</tr>
+								</tbody>
+							  </table>
+			  </td>
+				</tr>
+				</tbody>
+				</table>  
+</form>
+</body>
+</html>

+ 1 - 1
maxkey-web-maxkey/build.gradle

@@ -52,7 +52,7 @@ dependencies {
 	compile project(":maxkey-protocols:maxkey-protocol-tokenbased")
    	compile project(":maxkey-protocols:maxkey-protocol-oauth-2.0")
    	compile project(":maxkey-protocols:maxkey-protocol-saml-2.0")
-	
+	compile project(":maxkey-protocols:maxkey-protocol-jwt")
 	compile project(":maxkey-identitys:maxkey-identity-kafka")
 	
 }

+ 1 - 1
maxkey-web-maxkey/src/main/resources/application.properties

@@ -2,7 +2,7 @@
 #application
 application.title=MaxKey
 application.name=MaxKey
-application.formatted-version=v2.3.0 GA
+application.formatted-version=v2.4.0 GA
 
 #server port
 #server.port=80

+ 0 - 0
maxkey-web-maxkey/src/main/resources/templates/views/authorize/tokenbased_jwt_sso_submint.ftl → maxkey-web-maxkey/src/main/resources/templates/views/authorize/jwt_sso_submint.ftl


+ 5 - 4
settings.gradle

@@ -15,14 +15,15 @@ include 'maxkey-identitys:maxkey-identity-rest'
 
 //Protocol
 //include 'maxkey-protocols'
+include 'maxkey-protocols:maxkey-protocol-authorize'
 include 'maxkey-protocols:maxkey-protocol-oauth-2.0'
 include 'maxkey-protocols:maxkey-protocol-saml-2.0'
-include 'maxkey-protocols:maxkey-protocol-authorize'
-include 'maxkey-protocols:maxkey-protocol-desktop'
-include 'maxkey-protocols:maxkey-protocol-extendapi'
+include 'maxkey-protocols:maxkey-protocol-cas'
+include 'maxkey-protocols:maxkey-protocol-jwt'
 include 'maxkey-protocols:maxkey-protocol-formbased'
 include 'maxkey-protocols:maxkey-protocol-tokenbased'
-include 'maxkey-protocols:maxkey-protocol-cas'
+include 'maxkey-protocols:maxkey-protocol-extendapi'
+include 'maxkey-protocols:maxkey-protocol-desktop'
 
 //include 'maxkey-webs'
 //maxkey