2016.7.11 4:32
如今很多后台涉及很多手机登录授权管理,很多人使用shiro 或者spring security 解决,其中shiro 接入比较简单,但是security 接入入门水平就比较高了。如果不想接入任何的登录授权的话,啃官方文档的话。那就对了。接下来我们就结合spring AOP 来写一个简单的token管理,自定义注解来解决此授权问题。主要分为下面的几个步骤:
- tokenManager 的建立
- 自定义注解的建立
- 实现一个和User一样的类
- 结合AOP来解决节省多余的代码。
- 体验一下我们的tokenValid 的使用吧。
写一个具有时效性的tokenManager
@Component
public class TokenManager {
public static Map<String, Map<String,Object>> token = new HashMap<>();
private static Map<String, String> tokenMap = new ConcurrentHashMap<>();
public String createToken(String username) {
String token = UUID.randomUUID().toString();
tokenMap.put(token, username);
return token;
}
public Integer verifyToken(String token) {
/**
* 走后门
*/
Map<String,Object> map = new HashMap<>();
map.put("user_id", String.valueOf(15));
map.put("time",new Date().getTime());
TokenManager.token.put("1",map);
Map<String,Object> tokenMap = TokenManager.getToken(token);
if(tokenMap == null){
return null;
}
Assert.notNull(tokenMap.get("time"));
Assert.notNull(tokenMap.get("user_id"));
long time = Long.parseLong(tokenMap.get("time").toString()) ;
if (new Date().getTime() - time > 7 * 24 * 60 * 60 * 1000) {
TokenManager.token.remove(token);
return null;
}
tokenMap.put("time",new Date().getTime());
TokenManager.setToken(token,tokenMap);
return Integer.parseInt(tokenMap.get("user_id").toString());
}
public boolean checkToken(String token) {
return !StringUtils.isEmpty(token) && tokenMap.containsKey(token);
}
public synchronized String createToken(){
return UUID.randomUUID().toString().replace("-","");
}
public static Map<String, Map<String,Object>> getToken() {
return token;
}
public static Map<String,Object> getToken(String token) {
return TokenManager.token.get(token);
}
public synchronized static void setToken(String token,Map<String, Object> map) {
TokenManager.token.put(token,map);
}
}
然后我们只要在每个需要登录的接口处,判断获取userId 并且判断数据库内是否存在该用户即可。这时候AOP就派上用场了。不哆嗦我们来结合AOP来完成一个token认证吧。
自定义token
/**
* Created by zengfeng on 16/6/30.
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TokenValid {
}
实现一个和User一样的类(至于为什么这么干,我是想当修改用户信息的时候传递参数对象和我们token管理的user信息区分开来。)
public class Principle{
private String userName;
private String password;
/** 忽略属性和getter setter 方法 */
}
Spring Aop 的使用
@Aspect
@Order(10)
@Configuration
public class TokenAop {
@Autowired
TokenManager tokenManager;
@Autowired
AsUserMapper asUserMapper;
@Autowired
HttpServletRequest request;
@Pointcut("execution(* com.zf.controller.*.*(..))&&" + "@annotation(com.zf.config.TokenValid)")
public void tokenPointCut() {
}
@Around(value = "tokenPointCut()")
public Object addTokenToMethod(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
Object token = request.getParameter("token");
AsUser asUser = findUser(args,token);
Assert.notNull(asUser, "请重新登录");
injectUserObject(asUser, args,token);
return joinPoint.proceed(args);
}
private void injectUserObject(AsUser asUser, Object[] args,Object token) {
for (int i=0; i < args.length;i++)
if (args[i] instanceof Principle) {
args[i] = userConvertPrinciple(asUser);
break;
}
}
/**
* @param u
* @return
*/
private Object userConvertPrinciple(AsUser u) {
Principle principle = new Principle();
BeanUtils.copyProperties(u,principle);
return principle;
}
private AsUser findUser(Object[] args, Object token) {
Integer userId = tokenManager.verifyToken((String) token);
return asUserMapper.selectByPrimaryKey(userId);
}
}
下面我们来体验一下我们的tokenValid 的使用吧。
@RestController
@RequestMapping("/api/user")
public class UserController {
@TokenValid
@RequestMapping(value = "/setDefaultAddress",method = RequestMethod.POST)
public void setDefaultAddress(Principle principle,@RequestParam Integer uadId) throws ExpireException, NotSamePeopleException {
usersService.save(principle, uadId);
};
😄 spring 是不是很好玩?各位兄弟姐妹们。喜欢的点赞。
网友评论