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 \ No newline at end of file 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 +}