springsecurity6配置三

springsecurity配置多种登录方式,比如手机验证码登录、邮箱登录、微信小程序登录等,下面就以微信小程序登录为例进行讲解。

一、小程序用户实体实现springsecurity中的UserDetails接口

package com.school.information.core.security.entity;

import com.alibaba.fastjson.annotation.JSONField;
import com.school.information.entity.SysWechatUserEntity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class WechatAppUser implements UserDetails {
    /**
     * 微信小程序返回的session_key
     */
    private String sessionKey;

    /**
     * 小程序的基本信息
     *
     * @return
     */
    private SysWechatUserEntity sysWechatUser;

    @Override
    public Collection getAuthorities() {
        return null;
    }

    @Override
    @JSONField(serialize = false)
    public String getPassword() {
        return null;
    }

    @Override
    public String getUsername() {
        return sysWechatUser.getOpenid();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

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

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

二、小程序用户实现类实现springsecurity中的UserDetailsService接口

package com.school.information.core.service;

import com.school.information.core.exception.ServiceException;
import com.school.information.core.security.entity.SecurityUser;
import com.school.information.entity.SysUserEntity;
import com.school.information.enums.result.SysResultEnum;
import com.school.information.enums.status.EnabledEnum;
import com.school.information.service.SysMenuService;
import com.school.information.service.SysRoleService;
import com.school.information.service.SysUserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.Set;

@Service
@Slf4j
public class SecurityUserServiceImpl implements UserDetailsService {
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysMenuService menuService;
    @Resource
    private SysRoleService roleService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("##进入后台用户登录逻辑代码处理:{}", username);
        // 根据登录名获取用户信息
        SysUserEntity sysUser = sysUserService.getByPhone(username);
        if (Objects.isNull(sysUser)) {
            log.error("##登录用户:{}不存在", username);
            throw new ServiceException(SysResultEnum.USER_NAME_NO_EXISTED);
        } else if (EnabledEnum.DISABLE.equals(sysUser.getIsEnabled())) {
            log.error("##登录用户:{}已停用", username);
            throw new ServiceException(SysResultEnum.USER_DISABLED);
        }
        // 获取用户角色、权限信息  用户角色和权限信息保留一个即可
        SecurityUser securityUser = new SecurityUser();
        securityUser.setSysUser(sysUser);

        Set perms = menuService.findMenuByUserId(sysUser.getId());
        securityUser.setPermissions(perms);

        Set roles = roleService.findRoleByUserId(sysUser.getId());
        securityUser.setRoles(roles);

        return securityUser;
    }
}

三、小程序自定义验证继承AbstractAuthenticationToken类

package com.school.information.core.security.authen;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;

import java.util.Collection;

/**
 * 微信小程序登录token验证,模仿 WechatAppAuthenticationToken 重写编写
 */
public class WechatAppAuthenticationToken extends AbstractAuthenticationToken {
    private static final long serialVersionUID = 580L;
    private final Object principal;
    private Object credentials;

    public WechatAppAuthenticationToken(Object principal, Object credentials) {
        super((Collection) null);
        this.principal = principal;
        this.credentials = credentials;
        this.setAuthenticated(false);
    }

    public WechatAppAuthenticationToken(Object principal, Object credentials, Collection authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
    }

    public static WechatAppAuthenticationToken unauthenticated(Object principal, Object credentials) {
        return new WechatAppAuthenticationToken(principal, credentials);
    }

    public static WechatAppAuthenticationToken authenticated(Object principal, Object credentials, Collection authorities) {
        return new WechatAppAuthenticationToken(principal, credentials, authorities);
    }

    public Object getCredentials() {
        return this.credentials;
    }

    public Object getPrincipal() {
        return this.principal;
    }

    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        Assert.isTrue(!isAuthenticated, "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        super.setAuthenticated(false);
    }

    public void eraseCredentials() {
        super.eraseCredentials();
        this.credentials = null;
    }
}

四、小程序自定义身份验证管理器实现springsecurity中的AuthenticationProvider

package com.school.information.core.security.provider;

import cn.hutool.core.util.ObjectUtil;
import com.school.information.core.security.authen.WechatAppAuthenticationToken;
import com.school.information.core.security.entity.WechatAppUser;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * 微信小程序登录验证, 模仿 DaoAuthenticationProvider
 */
public class WechatAppUserAuthenticationProvider implements AuthenticationProvider {

    private UserDetailsService userDetailsService;

    public WechatAppUserAuthenticationProvider() {

    }

    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // 自定义小程序认证登录 根据小程序openid获取小程序用户信息
        WechatAppUser wechatAppUser = (WechatAppUser) userDetailsService.loadUserByUsername(authentication.getName());
        if (ObjectUtil.isEmpty(wechatAppUser)) {
            throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
        }
        // 注意要调用 authenticated() 方法 这个是认证通过了的
        WechatAppAuthenticationToken result = WechatAppAuthenticationToken.authenticated(wechatAppUser, authentication.getCredentials(), null);
        result.setDetails(authentication.getDetails());

        return result;
    }

    public boolean supports(Class authentication) {
        return WechatAppAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    protected UserDetailsService getUserDetailsService() {
        return this.userDetailsService;
    }
}

你可能感兴趣的:(java,spring,boot,spring,cloud)