springSecurity-oauth2默认用户身份验证转换器
package com.xy.tasty.mgr.security;
import com.xy.common.verify.Asserts;
import com.xy.tasty.core.cache.UserContextCache;
import com.xy.tasty.core.exception.UnBindOrganizationException;
import com.xy.tasty.core.exception.UnAuthenticationException;
import com.xy.tasty.core.exception.UnBindAuthorityException;
import com.xy.tasty.core.security.AuthUserContext;
import com.xy.tasty.core.security.UserContext;
import com.xy.tasty.core.service.UserInfoService;
import com.xy.tasty.dao.core.dict.RoleEnum;
import com.xy.tasty.dao.core.entity.UserInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
/**
* @author Canaan
* @date 2019/4/2 19:34
*/
@Component
public class CustomUserAuthenticationConverter extends DefaultUserAuthenticationConverter implements ApplicationContextAware {
private final static Logger LOGGER = LoggerFactory.getLogger(CustomUserAuthenticationConverter.class);
@Autowired
private UserContextCache userContextCache;
@Autowired
private UserInfoService userInfoService;
@Autowired
private ApplicationContext applicationContext;
@Override
public Authentication extractAuthentication(Map<String, ?> map) {
if (!map.containsKey(USERNAME) || map.get("id") == null) {
//不是密码账号验证
return null;
}
long beingTime = System.currentTimeMillis();
try {
String tokenName = "jti";
if (map.get(tokenName) == null) {
throw new InvalidTokenException("无效用户");
}
String token = map.get(tokenName).toString();
UserInfo userInfo;
Optional<UserInfo> userInfoOptional = this.userContextCache.getUser(token);
if (userInfoOptional.isPresent()) {
userInfo = userInfoOptional.get();
} else {
//验证用户的有效性
userInfo = this.getUserAndVerify(map);
if (userInfo == null) {
throw new InvalidTokenException("无效用户");
}
this.userContextCache.putUser(token, userInfo);
}
UserContext userContext = this.applicationContext.getBean(AuthUserContext.class, userInfo);
Collection<? extends GrantedAuthority> authorities = userContext.getAuthorities();
return new UsernamePasswordAuthenticationToken(userContext, "N/A", authorities);
} finally {
LOGGER.debug("------ userContext 解析时间:{} ms -------", System.currentTimeMillis() - beingTime);
}
}
/**
* 获取当前用户是到【用户中心】授权了.主要通过【用户中心】的用户id到数据库中查询
* 如果用户来源是【食安】那么必须验证账号相同
* 验证用户是否有资源操作【食安】,即产品权限
* 验证【用户中心】的外部用户id,与【食安】一致
* 【食安超级管理员】只能通过tastymgr / uums 端点授权
* 验证用户是否已经分配了具体的角色
* 验证用户是否被禁用了
*
* @author Canaan
* @date 2019/4/3 14:48
*/
private UserInfo getUserAndVerify(Map<String, ?> map) {
Asserts.state("uums".equalsIgnoreCase(map.get("sub").toString())); //只能是通过用户中心发放令牌
String userName = map.get("user_name").toString();
try {
UserInfo userInfo = this.userInfoService.getByOutId(Long.valueOf(map.get("id").toString())).orElse(null);
if (userInfo == null) {
throw new InvalidTokenException("非法用户请至【用户中心】授权");
}
//TODO 如果用户来源是食安,那么账号要保持一致
//TODO 根据食安用户id和产品代码。查询线上是否已经授权了产品
//TODO 验证 用户id与食安用户一致
//TODO 验证用户是否已经分配了具体的角色 2019/7/24 11:02
//如果是管理员,那么客户端授权id只能是 tastymgr / uums
if (userInfo.getRole() == RoleEnum.ADMIN) {
switch (map.get("client_id").toString()) {
case "tastymgr":
case "uums":
break;
default:
throw new InvalidTokenException("超管只能通过【tastymgr】端点来授权");
}
}
return userInfo;
} catch (UnAuthenticationException e) {
throw e;
} catch (UnBindOrganizationException | UnBindAuthorityException e) {
return null;
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
return null;
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
package com.xy.tasty.core.security;
import com.xy.common.verify.Asserts;
import com.xy.tasty.core.exception.UnBindOrganizationException;
import com.xy.tasty.core.service.BrandService;
import com.xy.tasty.core.service.StoreService;
import com.xy.tasty.dao.core.dict.RoleEnum;
import com.xy.tasty.dao.core.dict.UserStatusEnum;
import com.xy.tasty.dao.core.entity.Brand;
import com.xy.tasty.dao.core.entity.Store;
import com.xy.tasty.dao.core.entity.UserInfo;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
/**
* @author Canaan
* @date 2019/6/19 16:48
*/
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class AuthUserContext implements UserContext {
private Long id; //主键
private RoleEnum role; //用户角色
private String username; //登录账号
private Collection<UserContextGrantedAuthority> authorities; //权限集
private String nickname; //用户呢称
private String password; //登录密码
private boolean accountNonExpired; //账号没有过期
private boolean accountNonLocked; // 账号没有被锁定
private boolean credentialsNonExpired; //证书没有过期
private boolean enabled; //是否可用
private Long pointId; //指向id
@Autowired(required = false)
private BrandService brandService;
@Autowired(required = false)
private StoreService storeService;
public AuthUserContext() {
this.authorities = new HashSet<>();
}
public AuthUserContext(UserInfo userInfo) {
Asserts.notNull(userInfo);
this.id = userInfo.getId();
this.role = userInfo.getRole();
this.username = userInfo.getUsername();
UserContextGrantedAuthority authority = new UserContextGrantedAuthority("ROLE_" + userInfo.getRole());
this.authorities = Collections.singletonList(authority);
this.nickname = userInfo.getNickname();
this.password = null;
this.accountNonExpired = true;
this.accountNonLocked = true;
this.credentialsNonExpired = true;
this.enabled = userInfo.getStatus() == UserStatusEnum.ENABLED;
this.pointId = userInfo.getPointId();
}
/**
* 获取【门店用户】所持有的门店
*
* @return
*/
@Override
public Store getStore() {
if (getRole() != RoleEnum.STORE) {
throw new IllegalStateException("仅限于门店用户调用");
}
Asserts.notNull(this.storeService);
return this.storeService.getById(pointId).orElseThrow(UnBindOrganizationException::new);
}
/**
* 获取【品牌用户】所持有的品牌
*
* @return
*/
@Override
public Brand getBrand() {
if (getRole() != RoleEnum.BRAND) {
throw new IllegalStateException("仅限于品牌用户调用");
}
Asserts.notNull(this.brandService);
return this.brandService.getById(pointId).orElseThrow(UnBindOrganizationException::new);
}
public Long getPointId() {
return pointId;
}
public void setPointId(Long pointId) {
this.pointId = pointId;
}
public void setId(Long id) {
this.id = id;
}
public void setRole(RoleEnum role) {
this.role = role;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public Long getId() {
return id;
}
@Override
public RoleEnum getRole() {
return role;
}
@Override
public String getNickname() {
return nickname;
}
@Override
public String getUsername() {
return username;
}
public boolean isAccountNonExpired() {
return accountNonExpired;
}
public boolean isAccountNonLocked() {
return accountNonLocked;
}
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
public boolean isEnabled() {
return enabled;
}
@Override
public Collection<UserContextGrantedAuthority> getAuthorities() {
return authorities;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public void setAccountNonLocked(Boolean accountNonLocked) {
if (accountNonLocked == null) {
return;
}
this.accountNonLocked = accountNonLocked;
}
public void setAccountNonExpired(Boolean accountNonExpired) {
if (accountNonExpired == null) {
return;
}
this.accountNonExpired = accountNonExpired;
}
public void setCredentialsNonExpired(Boolean credentialsNonExpired) {
if (credentialsNonExpired == null) {
return;
}
this.credentialsNonExpired = credentialsNonExpired;
}
public void setAuthorities(Collection<UserContextGrantedAuthority> authorities) {
this.authorities.clear();
this.authorities.addAll(authorities);
}
public void setEnabled(Boolean enabled) {
if (enabled == null) {
return;
}
this.enabled = enabled;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
}