springSecurity-oauth2默认用户身份验证转换器( 方法上的注解权限authorities)

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);
        }
    }


    /**
     * <li>获取当前用户是到【用户中心】授权了.主要通过【用户中心】的用户id到数据库中查询</li>
     * <li>如果用户来源是【食安】那么必须验证账号相同</li>
     * <li>验证用户是否有资源操作【食安】,即产品权限</li>
     * <li>验证【用户中心】的外部用户id,与【食安】一致</li>
     * <li>【食安超级管理员】只能通过tastymgr / uums 端点授权</li>
     * <li>验证用户是否已经分配了具体的角色</li>
     * <li>验证用户是否被禁用了</li>
     *
     * @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);
    }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值