我们目前有一个系统,使用springdatajpa访问数据库,使用springmvc提供rest接口给网站系统,同时使用shiro提供权限控制,目前需要对外部系统提供接口,需要满足以下情况:*若目前已经存在了这样的接口,不再另外提供,同时权限部分得满足;*提供外部系统的接口权限使用token实现,即外部系统需要先获取到token,然后将token设置到cookie上,系统再根据token获取用户信息判断权限,token在一定时间内有效。*提供给外部系统的不能访问原系统的接口;
实现思路
每一个@RequestMapping可以配置多个不同的请求路径,对于外部接口提供的接口,添加API后缀即可区分,添加拦截器实现对后缀是API接口的拦截,在完成请求时通过封装将结果同一格式返回到前台,用户登录时,将token和用户对于的user信息保存到缓存中。
实现
多个用户登录踢出及怎样使用通达信dll函数接口,session过期处理拦截器
/**
* @类名 KickoutSessionControlFilter
* @描述 多个用户登录踢出及怎样使用通达信dll函数接口,session过期处理 拦截器
* @作者 zhuxl
* @创建日期 2016年12月30日 下午2:47:33
*/
public class KickoutSessionControlFilter implements Filter {
private Logger logger=Logger.getLogger(KickoutSessionControlFilter.class);
private UserSessionRedisService userSessionRedisService;
private UserService userService;
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest)req;
String url=request.getRequestURI();
if(url.matches('^.{0,}/api/w{1,}/w{1,}API.{0,}$')){//是外部接口访问,从cookie中获取token并登陆
Cookie[] cookies=request.getCookies();
if(cookies!=null&&cookies.length>0){
for(Cookie cookie:cookies){
if('token'.equalsIgnoreCase(cookie.getName())){
String token=cookie.getValue();
String userId=userSessionRedisService.get(SessionType.API, token, -1);
User user=userService.findById(userId);
if(user!=null){
Subject curUser=SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
user.getId(), user.getPassword());
try{
curUser.login(usernamePasswordToken);
}catch(Exception e){
e.printStackTrace();
}
request.getSession(true).setAttribute('user', user);
}
filterChain.doFilter(req, res);
return;
}
}
}
filterChain.doFilter(req, res);
return;
}
//web、微信登录 用户未登录,通过,后面使用shiro进行权限(角色)拦截
Subject subject = SecurityUtils.getSubject();
HttpServletResponse response = (HttpServletResponse) res;
if (!subject.isAuthenticated() && !subject.isRemembered()) {
filterChain.doFilter(req, res);
return;
}
Session 怎样使用通达信dll函数接口,session = subject.getSession(false);
if(怎样使用通达信dll函数接口,session==null){
filterChain.doFilter(req, res);
return;
}
User user=(User)怎样使用通达信dll函数接口,session.getAttribute('user');
SessionType type=(SessionType)怎样使用通达信dll函数接口,session.getAttribute('loginType');
if(user==null||type==null){
filterChain.doFilter(req, res);
return;
}
//获取用户怎样使用通达信dll函数接口,session
String 怎样使用通达信dll函数接口,sessionId=null;
if(type==SessionType.WECHAT){
怎样使用通达信dll函数接口,sessionId=userSessionRedisService.get(type,user.getOpenId(), -1);
}else if(type==SessionType.WEB){
怎样使用通达信dll函数接口,sessionId=userSessionRedisService.get(type,user.getId(),1800000);
}
if(StrUtil.isBlank(怎样使用通达信dll函数接口,sessionId)){
//用户怎样使用通达信dll函数接口,session已经失效
logger.info('登录失效了!');
try{
subject.logout();
}catch(Exception ex){
}
response.setStatus(510);
Map maps=new HashMap();
maps.put('code', ErrorCode.NoLogin);
maps.put('msg', '用户登录已失效!!');
response.getOutputStream().write(ReturnFormat.retParam(maps).getBytes());
return;
}else if(怎样使用通达信dll函数接口,session.getId().equals(怎样使用通达信dll函数接口,sessionId)){
//用户已经登录,并且是同一个怎样使用通达信dll函数接口,session,继续
logger.info('用户已登录系统!!');
filterChain.doFilter(req, res);
return;
}else if(type==SessionType.WECHAT){
//用户已经在其他地方登录了,对于微信,直接挤上去
try{
subject.logout();
}catch(Exception ex){
ex.printStackTrace();
}
logger.info('用户已经在其他地方登录了,登录类型为微信,将直接挤上去');
User newUser=userService.findByOpenId(user.getOpenId());
if(newUser!=null){//存在该openId
Subject curUser=SecurityUtils.getSubject();
Session newSession=curUser.getSession(true);
newSession.setAttribute('user', newUser);
newSession.setAttribute('loginType', SessionType.WECHAT);
newSession.setTimeout(1000*60*60*24);
userSessionRedisService.add(type,newUser.getOpenId(), newSession.getId().toString(),-1);
UsernamePasswordToken token = new UsernamePasswordToken(
newUser.getOpenId(), newUser.getPassword());
try{
curUser.login(token);
}catch(Exception e){
e.printStackTrace();
}
filterChain.doFilter(req, res);
}else{//不存在openID
response.setStatus(510);
Map maps=new HashMap();
maps.put('code', ErrorCode.NoLogin);
maps.put('msg', '用户未绑定账号!!');
response.getOutputStream().write(ReturnFormat.retParam(maps).getBytes());
}
return ;
}else if(type==SessionType.WEB){
//用户已经在其他地方登录了,对于web,直接退出
logger.info('用户已经在其他地方登录了,登录类型为:web,直接退出');
try{
subject.logout();
}catch(Exception ex){
ex.printStackTrace();
}
response.setStatus(510);
Map maps=new HashMap();
maps.put('code', ErrorCode.NoLogin);
maps.put('msg', '用户已经在其他地方登录了');
response.getOutputStream().write(ReturnFormat.retParam(maps).getBytes());
return ;
}
}
//初始化
public void init(FilterConfig config) throws ServletException {
WebApplicationContext wac =WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
userSessionRedisService=(UserSessionRedisService)wac.getBean('userSessionRedisServiceImpl');
userService=(UserService)wac.getBean('userServiceImpl');
}
}
错误编码
/**
* @类名 ErrorCode
* @描述 错误编码
* @作者 zhuxl
* @创建日期 2016年12月30日 下午4:28:38
*/
public enum ErrorCode {
/**
* ErrorCode NoLogin 未登录系统,需要退出
*/
NoLogin,
/**
* ErrorCode Error 普通错误,具体错看msg
*/
Error,
/**
* ErrorCode NoPermission 无权限访问
*/
NoPermission,
/**
* ErrorCode LossParam 缺少参数
*/
LossParam,
/**
* ErrorCode HasEntity 已经存在(唯一性存在)
*/
HasEntity,
/**
* ErrorCode NoEntity 没有对应的实体
*/
NoEntity,
/**
* ErrorCode HasLogin 已经登录了系统
*/
HasLogin,
/**
* ErrorCode OK 成功
*/
OK
}
Api调用返回结果
/**
* @类名 ApiMsg
* @描述 Api调用返回
* @作者 zhuxl
* @创建时间 2017-4-19下午02:21:33
*/
public class ApiMsg implements Serializable{
/**
* long serialVersionUID
*/
private static final long serialVersionUID = -5590788323134429419L;
/**
* int code 编码 -1 未登录,1 成功,0 其他错误
*/
private ErrorCode code;
/**
* String msg 信息
*/
private String msg;
/**
* Object result 返回结果
*/
private Object result;
public ErrorCode getCode() {
return code;
}
public void setCode(ErrorCode code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
public ApiMsg(ErrorCode code, String msg, Object result) {
super();
this.code = code;
this.msg = msg;
this.result = result;
}
public ApiMsg(Object result) {
this.code=ErrorCode.OK;
this.msg='成功';
this.result = result;
}
}
对于外部系统调用,将统一给出ApiMsg作为返回结果,拦截返回结果@ResponseBody
/**
* @类名 ApiResponseBodyAdvice
* @描述 对于外部系统调用,将统一给出ApiMsg作为返回结果
* @作者 zhuxl
* @创建时间 2017-5-26下午05:18:39
*/
@ControllerAdvice
public class ApiResponseBodyAdvice implements ResponseBodyAdvice
全局异常处理,对于前台调用返回510错误,外部接口调用还是返回200正常,由code代表是否正常,msg具体错误原因
API返回结果之前,自动退出,使得外部接口调用无怎样使用通达信dll函数接口,session信息
/**
* @类名 ApiInterceptor
* @描述 对API调用的接口进行拦截,退出其登录状态(前台将无JSESSIONID)
* @作者 zhuxl
* @创建时间 2017-4-21上午10:40:37
*/
public class ApiInterceptor extends HandlerInterceptorAdapter{
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
String url=request.getRequestURI();
if(url.matches('^.{0,}/api/w{1,}/w{1,}API.{0,}$')){
org.apache.shiro.subject.Subject curUser=SecurityUtils.getSubject();
if(curUser.isAuthenticated()||curUser.isRemembered()){
try{
curUser.logout();
}catch (Exception e) {
e.printStackTrace();
}
}
/*HttpSession 怎样使用通达信dll函数接口,session=request.getSession(false);
if(怎样使用通达信dll函数接口,session!=null){
怎样使用通达信dll函数接口,session.invalidate();
}*/
}
}
}
外部接口登录
/**
* loginApi
* @描述 外部接口登录,将返回一个token,token(32位)一天有效,过期后将无法使用,需要重新获取,重复调用将重复生成
* @作者 zhuxl
* @创建时间 2017-4-19下午03:21:45
* @param nameAndPwd
* @return
*/
@RequestMapping(value = {'loginAPI'}, method = RequestMethod.POST)
public String loginApi(@Valid @RequestBody LoginNameAndPwd nameAndPwd,BindingResult result){
if(result.hasFieldErrors()){
throw new PhyException(ErrorCode.Error,result.getFieldError().getDefaultMessage());
}
User user2 = userService.findByLoginName(nameAndPwd.getLoginName());
if (user2 == null) {
throw new PhyException(ErrorCode.Error,'当前登录用户不存在');
}
if (user2.getPassword().equals(CryptUtil.encrypt(nameAndPwd.getTextPwd(), user2.getSalt()))) {
String token=UUID.randomUUID().toString().replace('-', '');
userSessionRedisService.add(SessionType.API,token, user2.getId(),86400000L);
logger.info(new LogModel(true, 'user api login system success,loginName:'+user2.getLoginName()));
return token;
} else {
throw new PhyException(ErrorCode.Error,'登录名或者密码不正确');
}
}
对于俩种都需要的,添加一个请求url即可。
/**
* findMyStation
* @描述 查找我的监测站(包括状态)
* @作者 zhuxl
* @创建时间 2017年2月6日 下午1:51:04
* @param 怎样使用通达信dll函数接口,session
* @return
*/
@RequiresUser
@RequestMapping(value={'findMyStation','findMyStationAPI'},method=RequestMethod.GET)
public List findMyStation(HttpSession 怎样使用通达信dll函数接口,session){
User user=(User)怎样使用通达信dll函数接口,session.getAttribute('user');
if(user==null){
throw new PhyException(ErrorCode.NoLogin,'未登录系统');
}
Role role=user.getRole();
List stations=new ArrayList();
List stationTags=new ArrayList();
if(role.getRoleName().equals('admin')){
stations=stationService.findAll();
}else{
stations=stationService.findByArea(user.getArea().getId());
}
//此处省略
}
springmvc配置如下:
文章为作者独立观点,不代表股票交易接口观点