系统开发中的用户权限的两种流行实现。

用户权限,url拦截,这在系统开发是不可少的,也是很重要的一环。有时候,我们可能在页面隐藏掉某些功能,但是,一旦我们直接通过url访问,或者自己写代码去访问的时候,如果没有权限的控制,那么我们的私有数据将暴露。知道了其重要性,那么该怎么去实现一个管理url方便,且安全的权限系统呢。

其实现在市场上提供了很多第三方的安全框架,例如spring security,shrio。这些在工作中都是使用非常普遍的,又或者自己在spring mvc或者Struct框架中,使用拦截器去实现。又或者最原始的servlet中的拦截器。实现的方式有很多种,但是原理都是一样的。

而且最最常见的无非得经过三个过滤:

1.访问的url是否合法(带参的检查)

2.是否登录

3.是否对当前url拥有权限

第一步可要可不要。但是是否登录,是否对当前url拥有权限,则是必要的。

一般普遍且简单的权限系统,表设计:

1.用户表

2.角色表

3.url资源表

4.用户---角色表   (多对多)

5.角色---url资源表   (多对多)


现在不谈实现,先谈原理,走一遍流程:

用户登录------根据输入用户id拿用户整一条数据------如果拿不到,那么返回错误说该用户不存在,如果拿到了用户数据,比对输入的密码,比对是否过期等用户自定义的条件,比对正确,那么成功登录。若不正确,则返回错误的信息。若正确后,那么可以在request中拿到用户登录的日志,写进数据库。将用户数据存储到session中(或者自己使用redis搭建的缓存,这其实类似session)。成功登录以后,将会立刻跳转到主页url。此时此请求将要走权限系统了。

首先得判断是否登录了,如果session中有这个用户的数据,那么证明登录了,走过登录验证后,将走权限验证:根据url去找角色,根据用户去找角色,如果两者有共同角色,那么证明该用户拥有该url的权限。

整个流程就是这样了。

如何用代码去实现呢?

在spring mvc框架下,我总结两种流行的实现方式:

自己使用spring mvc提供的拦截器去实现:

首先springmvc配置文件配置:



		
			
			
			
			
			
		
	
这个配置的意思是:对/androidpublic/*.do          /Ad**/**/*.do的请求进行拦截,对/androidpublic/alogin.do          /androidpublic/logout.do忽略掉。

然后拦截器是:

com.app.zf.itsm.android.publics.interceptor.AdLoginHandlerIntercep

这是我一个项目里安卓服务端的拦截器:

public class AdLoginHandlerIntercep extends HandlerInterceptorAdapter{

	
	/**autor:cwy
	 * 00表示不是最初来源,01代表尚未登录。将登陆验证和url权限验证写在一起
	 * 说明:首先验证登录,在登录的基础上验证来源是否正确,最后验证是否有权限
	 * 权限验证这里有三种情况是不拦截的:1.url池里一个url都没有,2.url没有录入进资源管理或者,url没有一个宿主,3。url录入,且有宿主,但是另外的宿主没有分配权限
	 * 注意事项:一旦一个url录入进资源管理,必须先给他一个宿主(系统管理员),否则,所有人都可以访问这个url
	 */
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		PageData pd = new PageData();
		pd=new PageData(request);
		String token1=request.getParameter("TOKEN1");
		String orgin=request.getParameter("ORIGIN");
		String path=request.getRequestURI();
			if(StringUtils.isNotEmpty(RedisPool.get(token1)))              
			{
				
				if(StringUtils.isNotEmpty(request.getParameter("INFOR")))     //已登录,还需要验证签名(签名存在)
				{
					String token2=RedisPool.get(token1);       //获得真正的token
					String origin = MD5.md5(path+"?"+token2+orgin);   //获取token和url的MD5加密
					if(!origin.equals(pd.get("INFOR")))                    //对比签名,防止url被人拦截后,模拟发送请求
					{
						response.getWriter().print(InterceptorStatusConstant.NO_ORGIN);                                //不是最初来源
						return false;
					}
					else
					{
						//已登录,签名通过,还需要验证是否对url有访问权限
						String url=request.getServletPath();
						//找到所有的url
						List allUrlList = MemeryCacheManager.getResourceRoleCache().getList("ALL_URL_LIST", String.class); // 从缓存中读取系统中所有url集合,进行对比
						if (CollectionUtils.isEmpty(allUrlList)) {
							SysResourceService resourceService = (SysResourceService) SpringContextUtil.getBean("sysresourceservice");
							allUrlList = resourceService.findAllUrl();
						}
						
						if (CollectionUtils.isNotEmpty(allUrlList)) {            //若数据库存在url,且找不到url与请求的url相同,那么将不拦截;如果有相同,在验证是否url对应的角色与用户拥有的角色是否相同,相同则不拦截,不相同则拦截,如果对应的url对应的角色为null,则不拦截。
							for (String resURL : allUrlList) {
								if (StringUtils.startsWith(url, resURL)) {
									List atts = MemeryCacheManager.getResourceRoleCache().getList(resURL, ConfigAttribute.class); // 从缓存读取对应请求url,所包含的角色集合
									if (CollectionUtils.isEmpty(atts)) {
										SysResourceService resourceService = (SysResourceService) SpringContextUtil.getBean("sysresourceservice");
										atts = resourceService.findConfigAttByURL(resURL);           //通过url找url对应的角色,若找到了,执行下一步,找不到的话,代表url没有宿主,所以这个url可以被所有的用户访问
									}

									if (CollectionUtils.isNotEmpty(atts)) {
										Iterator ite = atts.iterator(); // 请求URL所对应的角色集合
										while (ite.hasNext()) {
											ConfigAttribute ca = ite.next();
											String needRole = ((SecurityConfig) ca).getAttribute();
											//从redis缓存中拿用户角色代码字符串,并转化成数组
											 JSONArray relecodesJson=JSON.parseArray(RedisPublicInforUtil.getRolesCodes(request));
											 Object rolecodes[]= relecodesJson.toArray();
											for (int i=0;i

第二种实现:使用spring security来实现

spring security 在市场上还是很受欢迎的。它的功能很强大,不仅仅是拦截,还提供单点登录,即后一个用户登录会挤掉前一个登录的用户(这是可配置的)。

来自当前正在开发的系统的一个spring security配置文件:




	
	
	
	
	 
	
  	
  	
  	
  	 
  	 
	
	
	
	
	
	
	
	
	
		
		
		
		
		
		
		

		
		
		
			
		

		
		
	
	
	
	
		
		
		
	

	
	
		
			
		
	

	
	
		
		
		
	
	
	
	
	
	
	

	
	
		
			
				org.springframework.security.messages
			
		
	
	

对于登录,spring security也帮我们做了,验证码是用了谷歌的

 


验证码:


	
		
			
				
					
						yes
						211,211,211
						47,79,79
						23
						75
						24
						1234567890
						4
						新宋体
						white
						com.google.code.kaptcha.impl.NoNoise
						com.google.code.kaptcha.impl.ShadowGimpy
					
				
			
		
	

点击登录提交:会走spring security框架:到达:UserDetailsService;一般情况下,我们需要实现它,重写

@Override
	public UserDetails loadUserByUsername(String arg0)
			throws UsernameNotFoundException {
		// TODO Auto-generated method stub
		return null;
	}
arg0代表的其实就是账号。这个方法里面需要放置的逻辑是:根据账号拿用户信息,包括基本信息和额外需要用到的信息,例如用户拥有的角色,用户所在的数据域等等,然后将其返回。框架会自动帮助我们去判断密码,账号是否到期等等。

一个实现实例:

用户实体类需要实现框架的UserDetails接口:这个接口是

public class SysUser extends BaseEntity implements UserDetails, Serializable {

	@Override
	public Collection getAuthorities() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getPassword() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getUsername() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isAccountNonExpired() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isAccountNonLocked() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isEnabled() {
		// TODO Auto-generated method stub
		return false;
	}
}

一个实现它的实例:

public class SysUser extends BaseEntity implements UserDetails, Serializable {
	private static final String mgrAccount = "admin";//系统管理员
	
	private static final long serialVersionUID = 1L;
	private String username; // 名称
	private String sex; // 性别
	private String loginId; // 登陆账号
	private String password; // 密码
	private String enName; // 英文名
	private String employeeId; // 员工ID
	private String post; // 岗位
	private String duty; // 职务
	private String email; // 邮箱
	private String qq;
	private String mobile; // 手机
	private String officePhone; // 办公电话
	private String dutyDesc; // 职责
	private String headImage; // 头像地址
	private Date birthday; // 生日
	private Date joinDate; // 入职日期
	private Date expiredDate; // 合同到期日期
	private String stateFlag; // 状态 1:在职,2:离职,3:待定
	private String showState; // 隐藏状态 y:显示,h:隐藏
	private String deleteFlag; // n:未删除
	private Integer orderBy; // 排序
	private String remark; // 备注
	private String companyId; // 公司ID
	

	private String phonecode; //手机唯一码

	

	@Transient
	public String getPhonecode() {
		return phonecode;
	}

	@Transient
	public void setPhonecode(String phonecode) {
		this.phonecode = phonecode;
	}

	// 临时
	private String birthdayFmt; // 格式化
	private String joinDateFmt; // 格式化
	private String expiredDateFmt; // 格式化
	private String expiredState; // 过期状态
	private String companyName; // 公司名称
	private String companyCode; // 公司编码
	private String companyType; // 公司类型

	private String orgId; // 组织ID
	private String orgName; // 组织名称
	private String parentOrgIds; // 父辈组织ID
	private String parentOrgNames; // 父辈组织
	private String virtualOrgId; // 虚拟组织ID
	private String virtualOrgName; // 虚拟组织名称
	private String postName; // 岗位名称
	private String dutyName; // 职务名称
	private String roleId; // 角色ID
	private boolean isManage; // 是否系统管理机构,属于该组织下的人员拥有查看全部数据权限
	private List roles; // 拥有的角色集合
	private List authlist = new ArrayList(); // spring_security验证角色编码
	List companyList; // 关联公司或服务商
	List userGroupList; // 所属班组
	private Date dutywatchadate; //排班的值班日期

	public SysUser() {
	}

	public SysUser(String resourceid, String username) {
		super();
		setResourceid(resourceid);
		this.username = username;
	}

	@Column(name = "USERNAME", length = 50)
	public String getUsername() {
		return this.username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Column(name = "SEX", length = 50)
	public String getSex() {
		return this.sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	@Column(name = "LOGIN_ID", length = 50)
	public String getLoginId() {
		return this.loginId;
	}

	public void setLoginId(String loginId) {
		this.loginId = loginId;
	}

	@Column(name = "PASSWORD", length = 32)
	public String getPassword() {
		return this.password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Column(name = "EN_NAME", length = 50)
	public String getEnName() {
		return this.enName;
	}

	public void setEnName(String enName) {
		this.enName = enName;
	}

	@Column(name = "EMPLOYEE_ID", length = 50)
	public String getEmployeeId() {
		return this.employeeId;
	}

	public void setEmployeeId(String employeeId) {
		this.employeeId = employeeId;
	}

	@Column(name = "POST", length = 50)
	public String getPost() {
		return this.post;
	}

	public void setPost(String post) {
		this.post = post;
	}

	@Column(name = "DUTY", length = 50)
	public String getDuty() {
		return duty;
	}

	public void setDuty(String duty) {
		this.duty = duty;
	}

	@Column(name = "EMAIL", length = 100)
	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	@Column(name = "QQ", length = 50)
	public String getQq() {
		return this.qq;
	}

	public void setQq(String qq) {
		this.qq = qq;
	}

	@Column(name = "MOBILE", length = 100)
	public String getMobile() {
		return this.mobile;
	}

	public void setMobile(String mobile) {
		this.mobile = mobile;
	}

	@Column(name = "OFFICE_PHONE", length = 100)
	public String getOfficePhone() {
		return this.officePhone;
	}

	public void setOfficePhone(String officePhone) {
		this.officePhone = officePhone;
	}

	@Column(name = "DUTY_DESC", length = 650)
	public String getDutyDesc() {
		return this.dutyDesc;
	}

	public void setDutyDesc(String dutyDesc) {
		this.dutyDesc = dutyDesc;
	}

	@Column(name = "HEAD_IMAGE", length = 150)
	public String getHeadImage() {
		return this.headImage;
	}

	public void setHeadImage(String headImage) {
		this.headImage = headImage;
	}

	@Temporal(TemporalType.DATE)
	@Column(name = "BIRTHDAY")
	public Date getBirthday() {
		return this.birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;

		birthdayFmt = birthday != null ? DateTimeUtil.formatDate(birthday) : "";
	}

	@Temporal(TemporalType.DATE)
	@Column(name = "JOIN_DATE")
	public Date getJoinDate() {
		return this.joinDate;
	}

	public void setJoinDate(Date joinDate) {
		this.joinDate = joinDate;

		joinDateFmt = joinDate != null ? DateTimeUtil.formatDate(joinDate) : "";
	}

	@Temporal(TemporalType.DATE)
	@Column(name = "EXPIRED_DATE")
	public Date getExpiredDate() {
		return expiredDate;
	}

	private boolean expiredBool = true; // 过期标志:默认有效

	public void setExpiredDate(Date expiredDate) {
		this.expiredDate = expiredDate;

		expiredDateFmt = expiredDate != null ? DateTimeUtil.formatDate(expiredDate) : "";

		if (null == expiredDate) {
			setExpiredState("长期");
		} else {
			if (DateTimeUtil.addDays(expiredDate, 1).compareTo(new Date()) < 0) { // 合同到期时间小与当前时间,账号过期
				setExpiredState("过期");
				expiredBool = false;
			} else {
				setExpiredState("有效");
			}
		}
	}

	@Column(name = "STATE_FLAG", length = 1)
	public String getStateFlag() {
		return stateFlag;
	}

	public void setStateFlag(String stateFlag) {
		this.stateFlag = stateFlag;
	}

	@Column(name = "SHOW_STATE", length = 1)
	public String getShowState() {
		return showState;
	}

	public void setShowState(String showState) {
		this.showState = showState;
	}

	@Column(name = "DELETE_FLAG", length = 1)
	public String getDeleteFlag() {
		return deleteFlag;
	}

	public void setDeleteFlag(String deleteFlag) {
		this.deleteFlag = deleteFlag;
	}

	@Column(name = "ORDER_BY")
	public Integer getOrderBy() {
		return this.orderBy;
	}

	public void setOrderBy(Integer orderBy) {
		this.orderBy = orderBy;
	}

	@Column(name = "REMARK", length = 500)
	public String getRemark() {
		return this.remark;
	}

	public void setRemark(String remark) {
		this.remark = remark;
	}

	@Column(name = "COMPANY_ID")
	public String getCompanyId() {
		return companyId;
	}

	public void setCompanyId(String companyId) {
		this.companyId = companyId;
	}

	/**
	 * 是否系统管理机构,属于该组织下的人员拥有查看全部数据权限
	 * 
	 * @return true:是(查看全部数据)、false:否(只能查看本公司数据)
	 */
	@Transient
	public boolean isManage() {
		if(isManage && mgrAccount.equals(this.getLoginId())){
			return true;
		}else{
			return false;
		}
	}

	public void setManage(boolean isManage) {
		this.isManage = isManage;
	}

	@Transient
	public List getRoles() {
		return roles;
	}

	public void setRoles(List roles) {
		this.roles = roles;

		// 组装用户拥有角色成spring security验证
		if (roles != null && roles.size() > 0) {
			for (SysRole role : roles) {
				authlist.add(new SimpleGrantedAuthority(role.getRoleCode()));
			}
		}
	}

	/**
	 * 过期标志
	 */
	@Transient
	public boolean isAccountNonExpired() {
		return expiredBool;
	}

	/**
	 * 锁定标志,在职状态才能进入系统
	 */
	@Transient
	public boolean isAccountNonLocked() {
		return StringUtils.equalsIgnoreCase(stateFlag, "1") ? true : false;
	}

	@Transient
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Transient
	public boolean isEnabled() {
		return true;
	}

	// 重写equals与hashCode,判断用户相等
	public boolean equals(Object rhs) {
		if (!(rhs instanceof SysUser) || (rhs == null)) {
			return false;
		}
		SysUser user = (SysUser) rhs;
		return (this.getPassword().equals(user.getPassword()) && this.getUsername().equals(user.getUsername()) && (this.isAccountNonExpired() == user.isAccountNonExpired())
				&& (this.isAccountNonLocked() == user.isAccountNonLocked()) && (this.isCredentialsNonExpired() == user.isCredentialsNonExpired()) && (this.isEnabled() == user.isEnabled()));
	}

	public int hashCode() {
		int code = 9792;
		for (GrantedAuthority authority : getAuthorities()) {
			code = code * (authority.hashCode() % 7);
		}
		if (this.getPassword() != null) {
			code = code * (this.getPassword().hashCode() % 7);
		}
		if (this.getUsername() != null) {
			code = code * (this.getUsername().hashCode() % 7);
		}
		if (this.isAccountNonExpired()) {
			code = code * -2;
		}
		if (this.isAccountNonLocked()) {
			code = code * -3;
		}
		if (this.isCredentialsNonExpired()) {
			code = code * -5;
		}
		if (this.isEnabled()) {
			code = code * -7;
		}
		return code;
	}

	// 组装用户拥有角色成spring security验证
	@Transient
	public Collection getAuthorities() {
		return authlist;
	}

	@Transient
	public String getRoleId() {
		return roleId;
	}

	public void setRoleId(String roleId) {
		this.roleId = roleId;
	}

	@Transient
	public String getOrgId() {
		return orgId;
	}

	public void setOrgId(String orgId) {
		this.orgId = orgId;
	}

	@Transient
	public String getOrgName() {
		return orgName;
	}

	public void setOrgName(String orgName) {
		this.orgName = orgName;
	}

	@Transient
	public String getParentOrgIds() {
		return parentOrgIds;
	}

	public void setParentOrgIds(String parentOrgIds) {
		this.parentOrgIds = parentOrgIds;
	}

	@Transient
	public String getParentOrgNames() {
		return parentOrgNames;
	}

	public void setParentOrgNames(String parentOrgNames) {
		this.parentOrgNames = parentOrgNames;
	}

	@Transient
	public String getVirtualOrgId() {
		return virtualOrgId;
	}

	public void setVirtualOrgId(String virtualOrgId) {
		this.virtualOrgId = virtualOrgId;
	}

	@Transient
	public String getVirtualOrgName() {
		return virtualOrgName;
	}

	public void setVirtualOrgName(String virtualOrgName) {
		this.virtualOrgName = virtualOrgName;
	}

	@Transient
	public String getPostName() {
		return postName;
	}

	public void setPostName(String postName) {
		this.postName = postName;
	}

	@Transient
	public String getBirthdayFmt() {
		return birthdayFmt;
	}

	public void setBirthdayFmt(String birthdayFmt) {
		this.birthdayFmt = birthdayFmt;
	}

	@Transient
	public String getJoinDateFmt() {
		return joinDateFmt;
	}

	public void setJoinDateFmt(String joinDateFmt) {
		this.joinDateFmt = joinDateFmt;
	}

	@Transient
	public String getExpiredDateFmt() {
		return expiredDateFmt;
	}

	public void setExpiredDateFmt(String expiredDateFmt) {
		this.expiredDateFmt = expiredDateFmt;
	}

	@Transient
	public String getExpiredState() {
		return expiredState;
	}

	public void setExpiredState(String expiredState) {
		this.expiredState = expiredState;
	}

	@Transient
	public String getCompanyName() {
		return companyName;
	}

	public void setCompanyName(String companyName) {
		this.companyName = companyName;
	}

	@Transient
	public String getCompanyCode() {
		return companyCode;
	}

	public void setCompanyCode(String companyCode) {
		this.companyCode = companyCode;

		String manageOrg = PropertiesUtil.get("SYS_MANAGE"); // 系统管理机构编码
		if (StringUtils.equals(companyCode, manageOrg))
			setManage(true);
	}

	@Transient
	public String getCompanyType() {
		return companyType;
	}

	public void setCompanyType(String companyType) {
		this.companyType = companyType;
	}

	@Transient
	public List getCompanyList() {
		return companyList;
	}

	public void setCompanyList(List companyList) {
		this.companyList = companyList;
	}
	
	@Transient
	public List getUserGroupList() {
		return userGroupList;
	}

	public void setUserGroupList(List userGroupList) {
		this.userGroupList = userGroupList;
	}
	
	@Transient
	@Temporal(TemporalType.DATE)
	public Date getDutywatchadate() {
		return dutywatchadate;
	}
	public void setDutywatchadate(Date dutywatchadate) {
		this.dutywatchadate = dutywatchadate;
	}

	@Transient
	public String getDutyName() {
		return dutyName;
	}

	public void setDutyName(String dutyName) {
		this.dutyName = dutyName;
	}
}




用户登录将走到这里来

public class MyUserDetailService implements UserDetailsService {

	private static Logger logger = LogManager.getLogger(MyUserDetailService.class);

	// 注入服务
	SysUserService sysUserService;

	SysOrganizationService sysOrganizationService;

	SysUserLoginLogService sysUserLoginLogService;
	
	@Autowired
	SysUserGroupService sysUserGroupService;

	public SysUser loadUserByUsername(String loginId) throws UsernameNotFoundException, DataAccessException {
		SysUser loginUser = new SysUser(); // 登录用户
		if (StringUtils.isNotEmpty(loginId)) {
			logger.info(loginId + " LOGIN...");

			loginUser = sysUserService.findUserByLoginId(loginId); // 通过loginId查询用户
			if (null != loginUser) {
				loginUser.setPostName(DictionaryELTag.getTextByCompanyId("D_Post", loginUser.getPost(),loginUser.getCompanyId()));

				// 查询用户拥有角色
				List roles = sysUserService.findSysRoleByUserId(loginUser.getResourceid());
				if (CollectionUtils.isNotEmpty(roles)){
					loginUser.setRoles(roles);
				}
				if (StringUtils.equals(loginUser.getCompanyType(), "1")) { // 1:公司
					List companyList = sysOrganizationService.findCompanyByType("2", loginUser.getCompanyId());
					loginUser.setCompanyList(companyList);
				} else if (StringUtils.equals(loginUser.getCompanyType(), "2")) { // 2:服务商
					List companyList = sysOrganizationService.findCompanyByType("1", loginUser.getCompanyId());
					loginUser.setCompanyList(companyList);
				}
				//查询所在班组(list)
				List groupList = sysUserGroupService.getUserGroupByUserid(loginUser.getResourceid());
				if (CollectionUtils.isNotEmpty(groupList)){
					loginUser.setUserGroupList(groupList);
				}
			} else {
				logger.info("用户名(" + loginId + ")不存在...");
				throw new UsernameNotFoundException("用户名(" + loginId + ")不存在...");
			}
		} else {
			throw new UsernameNotFoundException("用户名不能为空...");
		}

		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		String agent = request.getHeader("User-Agent").toUpperCase(); // 浏览器类型
		String screen_height = request.getParameter("screen_height"); // 分辨率高
		String screen_width = request.getParameter("screen_width"); // 分辨率宽
		String ip = getIpAddr(request);

		SysUserLoginLog loginLog = new SysUserLoginLog(loginUser.getResourceid(), loginUser.getUsername(), ip, agent, screen_height, screen_width, loginUser.getCompanyId());
		sysUserLoginLogService.save(loginLog); // 保存登录日志

		logger.info(loginId + " SUCCESS LOGIN...IP:" + ip);
		return loginUser;
	}

	/**
	 * 通过HttpServletRequest返回IP地址
	 * 
	 * @param request
	 *            HttpServletRequest
	 * @return ip String
	 */
	public String getIpAddr(HttpServletRequest request) throws RuntimeException {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		if (ip == null && ("0:0:0:0:0:0:0:1").equals(ip))
			ip = "127.0.0.1";
		return ip;
	}

	public SysUserService getSysUserService() {
		return sysUserService;
	}

	public void setSysUserService(SysUserService sysUserService) {
		this.sysUserService = sysUserService;
	}

	public SysOrganizationService getSysOrganizationService() {
		return sysOrganizationService;
	}

	public void setSysOrganizationService(SysOrganizationService sysOrganizationService) {
		this.sysOrganizationService = sysOrganizationService;
	}

	public SysUserLoginLogService getSysUserLoginLogService() {
		return sysUserLoginLogService;
	}

	public void setSysUserLoginLogService(SysUserLoginLogService sysUserLoginLogService) {
		this.sysUserLoginLogService = sysUserLoginLogService;
	}

}

返回一个用户,由框架给我们做验证密码,验证是否过期的动作。


登录成功后访问一个url:

走拦截器:

/**
 * TODO:1、拦截器
 */
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

	private FilterInvocationSecurityMetadataSource securityMetadataSource;

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		FilterInvocation fi = new FilterInvocation(request, response, chain);
		invoke(fi);
	}

	public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
		return this.securityMetadataSource;
	}

	public Class getSecureObjectClass() {
		return FilterInvocation.class;
	}

	public void invoke(FilterInvocation fi) throws IOException, ServletException {
		InterceptorStatusToken token = super.beforeInvocation(fi);
		try {
			fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
		} finally {
			super.afterInvocation(token, null);
		}
	}

	public SecurityMetadataSource obtainSecurityMetadataSource() {
		return this.securityMetadataSource;
	}

	public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) {
		this.securityMetadataSource = newSource;
	}

	public void destroy() {
	}

	public void init(FilterConfig arg0) throws ServletException {
	}

}

然后根据请求的url去找到该url对应的角色

public class MyInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

	private static Logger logger = LogManager.getLogger(MyInvocationSecurityMetadataSource.class);

	public MyInvocationSecurityMetadataSource() {
		logger.debug("===============================初始化=================================");
	}

	public Collection getAttributes(Object object) throws IllegalArgumentException {
		String url = ((FilterInvocation) object).getRequestUrl(); // 请求地址
		List allUrlList = MemeryCacheManager.getResourceRoleCache().getList("ALL_URL_LIST", String.class); // 从缓存中读取系统中所有url集合,进行对比
		if (CollectionUtils.isEmpty(allUrlList)) {
			SysResourceService resourceService = (SysResourceService) SpringContextUtil.getBean("sysresourceservice");
			allUrlList = resourceService.findAllUrl();
		}

		logger.info((SpringContextUtil.getUser() != null ? "USER:" + SpringContextUtil.getUser().getUsername():"用户没登陆") + " ACCESS_URL:" + url);

		
		if (CollectionUtils.isNotEmpty(allUrlList)) {
			for (String resURL : allUrlList) {
				if (StringUtils.startsWith(url, resURL)) {
					List atts = MemeryCacheManager.getResourceRoleCache().getList(resURL, ConfigAttribute.class); // 从缓存读取对应请求url,所包含的角色集合
					if (CollectionUtils.isEmpty(atts)) {
						SysResourceService resourceService = (SysResourceService) SpringContextUtil.getBean("sysresourceservice");
						atts = resourceService.findConfigAttByURL(resURL);
					}

					if (CollectionUtils.isNotEmpty(atts)) {
						return atts;
					} else {
						return null;
					}
				}
			} // end for
		}
		return null;
	}

	public boolean supports(Class clazz) {
		return true;
	}

	public Collection getAllConfigAttributes() {
		return null;
	}

}
若url对应的就是为null,则所有人都可以访问,否则返回角色的集合,到第三阶段:权限和是否登录的拦截:

public class MyAccessDecisionManager implements AccessDecisionManager {

	/**
	 * 根据用户的角色与URL拥有的角色对比,以确认是否有权限 authentication:访问者所拥有的角色 object:请求URL
	 * configAttributes:请求资源所拥有的角色
	 * 说明:如果在资源管理那边新增了一个url,那么务必给这个url分配一个宿主,否则,所有人(对这个资源无权限的用户)也可以访问
	 */
	public void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
		if (configAttributes == null)      //请求资源拥有的角色为null时,所有人都可以去访问这个资源
		{
			return;
		}
		// HttpServletRequest request = invocation.getHttpRequest();

		Object obj = authentication.getPrincipal();
		if (obj.toString().equals("anonymousUser")) {
			FilterInvocation invocation = (FilterInvocation) object;
			String fullUrl = invocation.getFullRequestUrl(); // 外部访问全地址
			String basePath = PropertiesUtil.get("SYS_BASE_PATH");
			if (StringUtils.startsWithIgnoreCase(fullUrl, basePath)) // 外部访问
				return;
		}

		Iterator ite = configAttributes.iterator(); // 请求URL所对应的角色集合
		while (ite.hasNext()) {
			ConfigAttribute ca = ite.next();
			String needRole = ((SecurityConfig) ca).getAttribute();
			for (GrantedAuthority ga : authentication.getAuthorities()) { // 用户所拥有角色
				if (StringUtils.equals(StringUtils.trim(needRole), StringUtils.trim(ga.getAuthority()))) {
					return;
				}
			}
		}
		throw new AccessDeniedException("请求失败,请检查您的权限...");
	}

	public boolean supports(ConfigAttribute configattribute) {
		return true;
	}

	public boolean supports(Class class1) {
		return true;
	}

}

有返回的,代表走通了,否则就是将抛出spring security提供的AccessDeniedException异常


本文完毕。















你可能感兴趣的:(系统开发中的用户权限的两种流行实现。)