Commit 6260e175018c629c450a755885dd11537b59ef98

Authored by 王通
1 parent c0ce3a4d

1.接口资源细粒度管理

src/main/java/com/bsth/entity/PasswordUser.java
1   -package com.bsth.entity;
2   -
3   -import javax.persistence.*;
4   -import java.util.Date;
5   -
6   -/**
7   - * 接口 密码 访问用户
8   - * Created by panzhao on 2017/3/26.
9   - */
10   -@Entity
11   -@Table(name = "interface_user")
12   -public class PasswordUser {
13   -
14   - @Id
15   - @GeneratedValue
16   - private Integer id;
17   -
18   - /** 访问密码 */
19   - private String pwd;
20   -
21   - /** 调用方名称 */
22   - private String callName;
23   -
24   - /** 创建日期 */
25   - @Column(updatable = false, name = "create_date", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
26   - private Date createDate;
27   -
28   - /** 备注 */
29   - private String remark;
30   -
31   - public Integer getId() {
32   - return id;
33   - }
34   -
35   - public void setId(Integer id) {
36   - this.id = id;
37   - }
38   -
39   - public String getPwd() {
40   - return pwd;
41   - }
42   -
43   - public void setPwd(String pwd) {
44   - this.pwd = pwd;
45   - }
46   -
47   - public String getCallName() {
48   - return callName;
49   - }
50   -
51   - public void setCallName(String callName) {
52   - this.callName = callName;
53   - }
54   -
55   - public String getRemark() {
56   - return remark;
57   - }
58   -
59   - public void setRemark(String remark) {
60   - this.remark = remark;
61   - }
62   -
63   - public Date getCreateDate() {
64   - return createDate;
65   - }
66   -
67   - public void setCreateDate(Date createDate) {
68   - this.createDate = createDate;
69   - }
70   -}
  1 +package com.bsth.entity;
  2 +
  3 +import javax.persistence.*;
  4 +import java.util.Date;
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * 接口 密码 访问用户
  9 + * Created by panzhao on 2017/3/26.
  10 + */
  11 +@Entity
  12 +@Table(name = "interface_user")
  13 +public class PasswordUser {
  14 +
  15 + @Id
  16 + @GeneratedValue
  17 + private Integer id;
  18 +
  19 + /** 访问密码 */
  20 + private String pwd;
  21 +
  22 + /** 调用方名称 */
  23 + private String callName;
  24 +
  25 + /** 创建日期 */
  26 + @Column(updatable = false, name = "create_date", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
  27 + private Date createDate;
  28 +
  29 + /** 备注 */
  30 + private String remark;
  31 +
  32 + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  33 + @JoinTable(name = "interface_users_resources",
  34 + joinColumns = @JoinColumn(name = "user_id"),
  35 + inverseJoinColumns = @JoinColumn(name = "resource_id"))
  36 + private List<Resource> resources;
  37 +
  38 + public Integer getId() {
  39 + return id;
  40 + }
  41 +
  42 + public void setId(Integer id) {
  43 + this.id = id;
  44 + }
  45 +
  46 + public String getPwd() {
  47 + return pwd;
  48 + }
  49 +
  50 + public void setPwd(String pwd) {
  51 + this.pwd = pwd;
  52 + }
  53 +
  54 + public String getCallName() {
  55 + return callName;
  56 + }
  57 +
  58 + public void setCallName(String callName) {
  59 + this.callName = callName;
  60 + }
  61 +
  62 + public String getRemark() {
  63 + return remark;
  64 + }
  65 +
  66 + public void setRemark(String remark) {
  67 + this.remark = remark;
  68 + }
  69 +
  70 + public Date getCreateDate() {
  71 + return createDate;
  72 + }
  73 +
  74 + public void setCreateDate(Date createDate) {
  75 + this.createDate = createDate;
  76 + }
  77 +
  78 + public List<Resource> getResources() {
  79 + return resources;
  80 + }
  81 +
  82 + public void setResources(List<Resource> resources) {
  83 + this.resources = resources;
  84 + }
  85 +}
... ...
src/main/java/com/bsth/entity/Resource.java 0 → 100644
  1 +package com.bsth.entity;
  2 +
  3 +import javax.persistence.*;
  4 +
  5 +/**
  6 + * @Author Hill
  7 + */
  8 +@Entity
  9 +@Table(name = "interface_resources")
  10 +public class Resource {
  11 +
  12 + @Id
  13 + @GeneratedValue
  14 + private Integer id;
  15 +
  16 + private String name;
  17 +
  18 + private String url;
  19 +
  20 + private String remark;
  21 +
  22 + public Integer getId() {
  23 + return id;
  24 + }
  25 +
  26 + public void setId(Integer id) {
  27 + this.id = id;
  28 + }
  29 +
  30 + public String getName() {
  31 + return name;
  32 + }
  33 +
  34 + public void setName(String name) {
  35 + this.name = name;
  36 + }
  37 +
  38 + public String getUrl() {
  39 + return url;
  40 + }
  41 +
  42 + public void setUrl(String url) {
  43 + this.url = url;
  44 + }
  45 +
  46 + public String getRemark() {
  47 + return remark;
  48 + }
  49 +
  50 + public void setRemark(String remark) {
  51 + this.remark = remark;
  52 + }
  53 +}
0 54 \ No newline at end of file
... ...
src/main/java/com/bsth/server_rs/AuthorizeInterceptor_IN.java
1   -package com.bsth.server_rs;
2   -
3   -import com.bsth.server_rs.exception.AesException;
4   -import com.bsth.service.UserService;
5   -import org.apache.commons.lang3.StringEscapeUtils;
6   -import org.apache.cxf.interceptor.Fault;
7   -import org.apache.cxf.message.Message;
8   -import org.apache.cxf.phase.AbstractPhaseInterceptor;
9   -import org.apache.cxf.phase.Phase;
10   -import org.eclipse.jetty.util.MultiMap;
11   -import org.eclipse.jetty.util.UrlEncoded;
12   -import org.slf4j.Logger;
13   -import org.slf4j.LoggerFactory;
14   -import org.springframework.beans.BeansException;
15   -import org.springframework.context.ApplicationContext;
16   -import org.springframework.context.ApplicationContextAware;
17   -import org.springframework.stereotype.Component;
18   -
19   -import java.security.MessageDigest;
20   -import java.util.Arrays;
21   -import java.util.HashMap;
22   -import java.util.Map;
23   -import java.util.Set;
24   -
25   -/**
26   - * rest 接口授权校验(IN 输入拦截)
27   - * Created by panzhao on 2017/3/28.
28   - */
29   -@Component
30   -public class AuthorizeInterceptor_IN extends AbstractPhaseInterceptor<Message> implements ApplicationContextAware {
31   -
32   - private static final String SIGN = "sign";
33   - private static final String TIMESTAMP = "timestamp";
34   - private static final String NONCE = "nonce";
35   - private static final String PASSWORD = "password";
36   - private static final int MAX_TIME_DIFF = 1000 * 60 * 10;
37   - private static Map<String, String> pwd2nonceMap;
38   -
39   - static UserService userService;
40   -
41   - static Logger logger = LoggerFactory.getLogger(AuthorizeInterceptor_IN.class);
42   -
43   - public AuthorizeInterceptor_IN() {
44   - super(Phase.RECEIVE);
45   - }
46   -
47   - static {
48   - pwd2nonceMap = new HashMap<>();
49   - }
50   -
51   - @Override
52   - public void handleMessage(Message message) throws Fault {
53   -
54   - long t = System.currentTimeMillis();
55   - if (message.get(Message.QUERY_STRING) == null) {
56   - throw new AesException(AesException.MISS_SIGN);
57   - }
58   -
59   - //放行wadl
60   - if(message.get(Message.QUERY_STRING).equals("_wadl")
61   - && message.get(Message.PATH_INFO).equals("/webservice/rest")){
62   - return ;
63   - }
64   -
65   - //获取参数,不包括 url 路径参数 只包括?号之后的
66   - String queryString = StringEscapeUtils.unescapeHtml4(message.get(Message.QUERY_STRING).toString());
67   - MultiMap<String> params = new MultiMap<>();
68   - UrlEncoded.decodeTo(queryString, params, "utf-8");
69   - Map<String, String> map = multi2One(params);
70   -
71   - if (!map.containsKey(SIGN)) {
72   - throw new AesException(AesException.MISS_SIGN);
73   - }
74   - if (!map.containsKey(TIMESTAMP)) {
75   - throw new AesException(AesException.MISS_TIMESTAMP);
76   - }
77   -
78   - try{
79   - long timestamp = Long.parseLong(map.get(TIMESTAMP));
80   - if(Math.abs(t - timestamp) > MAX_TIME_DIFF){
81   - throw new AesException(AesException.INVALID_TIMESTAMP);
82   - }
83   - }catch(Exception e){
84   - throw new AesException(AesException.INVALID_TIMESTAMP);
85   - }
86   -
87   - if (!map.containsKey(NONCE)) {
88   - throw new AesException(AesException.MISS_NONCE);
89   - }
90   - if (!map.containsKey(PASSWORD)) {
91   - throw new AesException(AesException.MISS_PWD);
92   - }
93   -
94   - String prevNonce = pwd2nonceMap.get(map.get(PASSWORD));
95   - if(prevNonce != null && prevNonce.equals(map.get(NONCE)))
96   - throw new AesException(AesException.NO_RANDOM_NONCE);
97   -
98   - if (userService.get(map.get(PASSWORD)) == null) {
99   - throw new AesException(AesException.INVALID_PWD);
100   - }
101   -
102   - String sign = map.get(SIGN);
103   - map.remove(SIGN);
104   - String sh1 = "";
105   - try {
106   - sh1 = getSHA1(map);
107   - } catch (Exception e) {
108   - throw new AesException(AesException.SIGN_CHECK_ERROR);
109   - }
110   -
111   - if (!sign.equals(sh1)) {
112   - throw new AesException(AesException.SIGN_CHECK_FAIL);
113   - }
114   - }
115   -
116   - public static Map<String, String> multi2One(MultiMap<String> params) {
117   - Map<String, String> map = new HashMap<>();
118   - Set<String> ks = params.keySet();
119   - for (String k : ks) {
120   - map.put(k, params.getString(k));
121   - }
122   - return map;
123   - }
124   -
125   -
126   - public static String getSHA1(Map<String, String> map) throws Exception {
127   -
128   - try {
129   - String[] array = new String[map.size()];
130   - map.values().toArray(array);
131   - StringBuffer sb = new StringBuffer();
132   -
133   - // 字符串排序
134   - Arrays.sort(array);
135   - for (int i = 0; i < array.length; i++) {
136   - sb.append(array[i]);
137   - }
138   - String str = sb.toString();
139   - // SHA1签名生成
140   - MessageDigest md = MessageDigest.getInstance("SHA-1");
141   - md.update(str.getBytes());
142   - byte[] digest = md.digest();
143   -
144   - StringBuffer hexstr = new StringBuffer();
145   - String shaHex = "";
146   - for (int i = 0; i < digest.length; i++) {
147   - shaHex = Integer.toHexString(digest[i] & 0xFF);
148   - if (shaHex.length() < 2) {
149   - hexstr.append(0);
150   - }
151   - hexstr.append(shaHex);
152   - }
153   - return hexstr.toString();
154   - } catch (Exception e) {
155   - logger.error("", e);
156   - throw e;
157   - }
158   - }
159   -
160   - @Override
161   - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
162   - userService = applicationContext.getBean(UserService.class);
163   - }
164   -}
  1 +package com.bsth.server_rs;
  2 +
  3 +import com.bsth.entity.PasswordUser;
  4 +import com.bsth.entity.Resource;
  5 +import com.bsth.server_rs.exception.AesException;
  6 +import com.bsth.service.UserService;
  7 +import org.apache.commons.lang3.StringEscapeUtils;
  8 +import org.apache.cxf.interceptor.Fault;
  9 +import org.apache.cxf.message.Message;
  10 +import org.apache.cxf.phase.AbstractPhaseInterceptor;
  11 +import org.apache.cxf.phase.Phase;
  12 +import org.eclipse.jetty.util.MultiMap;
  13 +import org.eclipse.jetty.util.UrlEncoded;
  14 +import org.slf4j.Logger;
  15 +import org.slf4j.LoggerFactory;
  16 +import org.springframework.beans.BeansException;
  17 +import org.springframework.context.ApplicationContext;
  18 +import org.springframework.context.ApplicationContextAware;
  19 +import org.springframework.stereotype.Component;
  20 +import org.springframework.util.AntPathMatcher;
  21 +import org.springframework.util.PathMatcher;
  22 +
  23 +import java.security.MessageDigest;
  24 +import java.util.Arrays;
  25 +import java.util.HashMap;
  26 +import java.util.Map;
  27 +import java.util.Set;
  28 +
  29 +/**
  30 + * rest 接口授权校验(IN 输入拦截)
  31 + * Created by panzhao on 2017/3/28.
  32 + */
  33 +@Component
  34 +public class AuthorizeInterceptor_IN extends AbstractPhaseInterceptor<Message> implements ApplicationContextAware {
  35 +
  36 + private static final String SIGN = "sign";
  37 + private static final String TIMESTAMP = "timestamp";
  38 + private static final String NONCE = "nonce";
  39 + private static final String PASSWORD = "password";
  40 + private static final int MAX_TIME_DIFF = 1000 * 60 * 10;
  41 + private static Map<String, String> pwd2nonceMap;
  42 +
  43 + static UserService userService;
  44 +
  45 + static Logger logger = LoggerFactory.getLogger(AuthorizeInterceptor_IN.class);
  46 +
  47 + private static PathMatcher matcher = new AntPathMatcher();
  48 +
  49 + public AuthorizeInterceptor_IN() {
  50 + super(Phase.RECEIVE);
  51 + }
  52 +
  53 + static {
  54 + pwd2nonceMap = new HashMap<>();
  55 + }
  56 +
  57 + @Override
  58 + public void handleMessage(Message message) throws Fault {
  59 +
  60 + long t = System.currentTimeMillis();
  61 + if (message.get(Message.QUERY_STRING) == null) {
  62 + throw new AesException(AesException.MISS_SIGN);
  63 + }
  64 +
  65 + //放行wadl
  66 + if(message.get(Message.QUERY_STRING).equals("_wadl")
  67 + && message.get(Message.PATH_INFO).equals("/webservice/rest")){
  68 + return ;
  69 + }
  70 +
  71 + //获取参数,不包括 url 路径参数 只包括?号之后的
  72 + String queryString = StringEscapeUtils.unescapeHtml4(message.get(Message.QUERY_STRING).toString());
  73 + MultiMap<String> params = new MultiMap<>();
  74 + UrlEncoded.decodeTo(queryString, params, "utf-8");
  75 + Map<String, String> map = multi2One(params);
  76 +
  77 + if (!map.containsKey(SIGN)) {
  78 + throw new AesException(AesException.MISS_SIGN);
  79 + }
  80 + if (!map.containsKey(TIMESTAMP)) {
  81 + throw new AesException(AesException.MISS_TIMESTAMP);
  82 + }
  83 +
  84 + try{
  85 + long timestamp = Long.parseLong(map.get(TIMESTAMP));
  86 + if(Math.abs(t - timestamp) > MAX_TIME_DIFF){
  87 + throw new AesException(AesException.INVALID_TIMESTAMP);
  88 + }
  89 + }catch(Exception e){
  90 + throw new AesException(AesException.INVALID_TIMESTAMP);
  91 + }
  92 +
  93 + if (!map.containsKey(NONCE)) {
  94 + throw new AesException(AesException.MISS_NONCE);
  95 + }
  96 + if (!map.containsKey(PASSWORD)) {
  97 + throw new AesException(AesException.MISS_PWD);
  98 + }
  99 +
  100 + String prevNonce = pwd2nonceMap.get(map.get(PASSWORD));
  101 + if(prevNonce != null && prevNonce.equals(map.get(NONCE)))
  102 + throw new AesException(AesException.NO_RANDOM_NONCE);
  103 +
  104 + if (userService.get(map.get(PASSWORD)) == null) {
  105 + throw new AesException(AesException.INVALID_PWD);
  106 + }
  107 +
  108 + String sign = map.get(SIGN);
  109 + map.remove(SIGN);
  110 + String sh1 = "";
  111 + try {
  112 + sh1 = getSHA1(map);
  113 + } catch (Exception e) {
  114 + throw new AesException(AesException.SIGN_CHECK_ERROR);
  115 + }
  116 +
  117 + if (!sign.equals(sh1)) {
  118 + throw new AesException(AesException.SIGN_CHECK_FAIL);
  119 + }
  120 +
  121 + validate(map, message);
  122 + }
  123 +
  124 + private static void validate(Map<String, String> map, Message message) {
  125 + PasswordUser user = userService.get(map.get(PASSWORD));
  126 + if (user.getResources().size() > 0) {
  127 + boolean isMatch = false;
  128 + String uri = (String) message.get(Message.REQUEST_URI);
  129 + for (Resource resource : user.getResources()) {
  130 + if (matcher.match(resource.getUrl(), uri)) {
  131 + isMatch = true;
  132 + break;
  133 + }
  134 + }
  135 + if (!isMatch) {
  136 + throw new AesException(AesException.INVALID_URI);
  137 + }
  138 + }
  139 + }
  140 +
  141 + public static Map<String, String> multi2One(MultiMap<String> params) {
  142 + Map<String, String> map = new HashMap<>();
  143 + Set<String> ks = params.keySet();
  144 + for (String k : ks) {
  145 + map.put(k, params.getString(k));
  146 + }
  147 + return map;
  148 + }
  149 +
  150 +
  151 + public static String getSHA1(Map<String, String> map) throws Exception {
  152 +
  153 + try {
  154 + String[] array = new String[map.size()];
  155 + map.values().toArray(array);
  156 + StringBuffer sb = new StringBuffer();
  157 +
  158 + // 字符串排序
  159 + Arrays.sort(array);
  160 + for (int i = 0; i < array.length; i++) {
  161 + sb.append(array[i]);
  162 + }
  163 + String str = sb.toString();
  164 + // SHA1签名生成
  165 + MessageDigest md = MessageDigest.getInstance("SHA-1");
  166 + md.update(str.getBytes());
  167 + byte[] digest = md.digest();
  168 +
  169 + StringBuffer hexstr = new StringBuffer();
  170 + String shaHex = "";
  171 + for (int i = 0; i < digest.length; i++) {
  172 + shaHex = Integer.toHexString(digest[i] & 0xFF);
  173 + if (shaHex.length() < 2) {
  174 + hexstr.append(0);
  175 + }
  176 + hexstr.append(shaHex);
  177 + }
  178 + return hexstr.toString();
  179 + } catch (Exception e) {
  180 + logger.error("", e);
  181 + throw e;
  182 + }
  183 + }
  184 +
  185 + @Override
  186 + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  187 + userService = applicationContext.getBean(UserService.class);
  188 + }
  189 +}
... ...
src/main/java/com/bsth/server_rs/exception/AesException.java
1   -package com.bsth.server_rs.exception;
2   -
3   -/**
4   - * Created by panzhao on 2017/3/28.
5   - */
6   -public class AesException extends RuntimeException {
7   -
8   - public final static int OK = 0;
9   - public final static int MISS_SIGN = -30001;
10   - public final static int MISS_TIMESTAMP = -30002;
11   - public final static int MISS_NONCE = -30003;
12   - public final static int NO_RANDOM_NONCE = -30005;
13   - public final static int MISS_PWD = -30004;
14   - public final static int SIGN_CHECK_ERROR = -40001;
15   - public final static int SIGN_CHECK_FAIL = -40002;
16   - public final static int INVALID_PWD = -40003;
17   - public final static int INVALID_TIMESTAMP = -40004;
18   -
19   - private int code;
20   -
21   - private static String getMessage(int code) {
22   - switch (code) {
23   - case MISS_SIGN:
24   - return "sign参数丢失";
25   - case MISS_TIMESTAMP:
26   - return "timestamp参数丢失";
27   - case MISS_NONCE:
28   - return "nonce参数丢失";
29   - case NO_RANDOM_NONCE:
30   - return "nonce参数异常";
31   - case MISS_PWD:
32   - return "密码参数丢失";
33   - case INVALID_PWD:
34   - return "无效的密码";
35   - case SIGN_CHECK_ERROR:
36   - return "签名校验时出现异常";
37   - case SIGN_CHECK_FAIL:
38   - return "无效的签名";
39   - case INVALID_TIMESTAMP:
40   - return "无效的时间戳";
41   - default:
42   - return null;
43   - }
44   - }
45   -
46   - public int getCode() {
47   - return code;
48   - }
49   -
50   - public AesException(int code) {
51   - super(getMessage(code));
52   - this.code = code;
53   - }
54   -}
  1 +package com.bsth.server_rs.exception;
  2 +
  3 +/**
  4 + * Created by panzhao on 2017/3/28.
  5 + */
  6 +public class AesException extends RuntimeException {
  7 +
  8 + public final static int OK = 0;
  9 + public final static int MISS_SIGN = -30001;
  10 + public final static int MISS_TIMESTAMP = -30002;
  11 + public final static int MISS_NONCE = -30003;
  12 + public final static int NO_RANDOM_NONCE = -30005;
  13 + public final static int MISS_PWD = -30004;
  14 + public final static int SIGN_CHECK_ERROR = -40001;
  15 + public final static int SIGN_CHECK_FAIL = -40002;
  16 + public final static int INVALID_PWD = -40003;
  17 + public final static int INVALID_TIMESTAMP = -40004;
  18 + public final static int INVALID_URI = -40005;
  19 +
  20 + private int code;
  21 +
  22 + private static String getMessage(int code) {
  23 + switch (code) {
  24 + case MISS_SIGN:
  25 + return "sign参数丢失";
  26 + case MISS_TIMESTAMP:
  27 + return "timestamp参数丢失";
  28 + case MISS_NONCE:
  29 + return "nonce参数丢失";
  30 + case NO_RANDOM_NONCE:
  31 + return "nonce参数异常";
  32 + case MISS_PWD:
  33 + return "密码参数丢失";
  34 + case INVALID_PWD:
  35 + return "无效的密码";
  36 + case SIGN_CHECK_ERROR:
  37 + return "签名校验时出现异常";
  38 + case SIGN_CHECK_FAIL:
  39 + return "无效的签名";
  40 + case INVALID_TIMESTAMP:
  41 + return "无效的时间戳";
  42 + case INVALID_URI:
  43 + return "无效的URI";
  44 + default:
  45 + return null;
  46 + }
  47 + }
  48 +
  49 + public int getCode() {
  50 + return code;
  51 + }
  52 +
  53 + public AesException(int code) {
  54 + super(getMessage(code));
  55 + this.code = code;
  56 + }
  57 +}
... ...