生成token和驗證token機制
阿新 • • 發佈:2018-12-25
1.生成token是一個spring控制器
基於專案和專案之間的呼叫祕鑰生成之後放redis,兩小時後失效
package com.csair.openapi.controller.basic; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import com.csair.openapi.basic.annotation.WEBApi; import com.csair.openapi.qo.sub.TokenCredential; import com.csair.openapi.vo.sub.TokenSuccess; @RestController @RequestMapping("/credential") public class TokenCredentialController { @Autowired private RedisTemplate<String, String> redisTemplate; private Map<String, String> key = new HashMap<String, String>(); @PostConstruct public void init() { key.put("lps", "lrKvmMg3h9c8UQsvzDn0S4X"); } @RequestMapping(value = "/getToken") @ResponseBody @WEBApi public Object export(HttpServletRequest request,HttpServletResponse response,@RequestBody TokenCredential limitsAuthority) throws Exception { TokenSuccess tokenSuccess = new TokenSuccess(); if (limitsAuthority!=null&&limitsAuthority.getAppid()!=null&&limitsAuthority.getSecret()!=null) {//校驗使用者是否有許可權 String appid= limitsAuthority.getAppid(); String secretPass =(String) key.get(appid); String secret = limitsAuthority.getSecret(); if (secret.equals(secretPass)) { String Timestamp= System.currentTimeMillis()+""; String token = md5Password(appid+secretPass+System.currentTimeMillis()+Timestamp); redisTemplate.opsForValue().set(token, Timestamp,7200, TimeUnit.SECONDS);//token和驗證碼對應的放到redis裡面 ,2小時秒過期 tokenSuccess.setAccess_token(token); tokenSuccess.setExpires_in("7200"); return tokenSuccess; }else{ throw new RuntimeException("invalid secret"); } } throw new RuntimeException("invalid appid"); } /** * 生成32位md5碼 * @param password * @return */ public static String md5Password(String password) { try { // 得到一個資訊摘要器 MessageDigest digest = MessageDigest.getInstance("md5"); byte[] result = digest.digest(password.getBytes()); StringBuffer buffer = new StringBuffer(); // 把每一個byte 做一個與運算 0xff; for (byte b : result) { // 與運算 int number = b & 0xff;// 加鹽 String str = Integer.toHexString(number); if (str.length() == 1) { buffer.append("0"); } buffer.append(str); } // 標準的md5加密後的結果 return buffer.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return ""; } } }
2.用java自定義註解引入aop來鑑權
package com.csair.openapi.basic.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Inherited @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface AuthToken { }
package com.csair.openapi.basic.aspect; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.Ordered; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import com.csair.cocc.basic.constant.EnvironmentEnum; import com.csair.openapi.basic.annotation.AuthToken; @Component @Aspect public class AuthTokenDecorator implements Ordered { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private RedisTemplate<String, String> redisTemplate; @Value("${environment}") private String environment; @Around("within(com.csair.**.controller.**.*) && @annotation(authToken)") public Object decorate(ProceedingJoinPoint pjp, AuthToken authToken) throws Throwable { if (EnvironmentEnum.DEV.getValue().equals(environment)) {//如果是開發環境 return pjp.proceed();//這個是可以繼續傳輸物件到Controller的邏輯 } Object[] obj = pjp.getArgs(); HttpServletRequest request = (HttpServletRequest) obj[0]; String accessToken = request.getParameter("accessToken"); logger.info("accessToken值為:"+accessToken); if (StringUtils.isEmpty(accessToken)) { throw new RuntimeException("token is null"); }else { String timestamp = redisTemplate.opsForValue().get(accessToken); if (StringUtils.isEmpty(timestamp)) { throw new RuntimeException("Invalid token"); } } return pjp.proceed(); } public int getOrder() { return 9; } }
引用redis的配置!
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<context:property-placeholder location="classpath:redis.properties" />
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="5000" />
<property name="maxIdle" value="2000" />
<property name="maxWaitMillis" value="4000" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
</bean>
<bean id="redisSentinelConfiguration"
class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
<property name="master">
<bean class="org.springframework.data.redis.connection.RedisNode">
<property name="name" value="${redis.master.name}"></property>
</bean>
</property>
<property name="sentinels">
<set>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.sentinel1.host}"></constructor-arg>
<constructor-arg name="port" value="${redis.sentinel1.port}"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.sentinel2.host}"></constructor-arg>
<constructor-arg name="port" value="${redis.sentinel2.port}"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.sentinel3.host}"></constructor-arg>
<constructor-arg name="port" value="${redis.sentinel3.port}"></constructor-arg>
</bean>
</set>
</property>
</bean>
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="password" value="${redis.password}" />
<property name="poolConfig" ref="jedisPoolConfig" />
<constructor-arg ref="redisSentinelConfiguration" />
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="keySerializer">
<bean
class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean
class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="hashKeySerializer">
<bean
class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="hashValueSerializer">
<bean
class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
</bean>
</beans>
最重要的是Controller的入參要加上HttpServletRequest request
@RequestMapping(value = "/saveCargoPlaneUploadLpsInfo", method = RequestMethod.POST)
@ResponseBody
@WEBApi
@AuthToken
public Object saveCargoPlaneUploadLpsInfo(HttpServletRequest request,@RequestBody CargoPlaneUploadLpsInfoDto param)