若依系统(Security)增加微信小程序登录(自定义登录)

若依系统(分离版后端)自带的账号验证是基于 

UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);

验证,然后在系统中controller或service类中 SecurityUtils 工具类中直接可获取用户或用户ID等

SecurityUtils.getLoginUser().getUser();

现在想实现,微信小程序通过code等登录后返回和之前一样的token后原逻辑中的SecurityUtils一样可以获取到,则需要自定义扩展登录类。废话不多说,上代码:

类似于UsernamePasswordAuthenticationToken类,自定义AuthCodeAuthenticationToken.java

在这个位置:

AuthCodeAuthenticationToken.java:

package com.ruoyi.framework;

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

import java.util.Collection;

public class AuthCodeAuthenticationToken extends AbstractAuthenticationToken {

    private final Object principal;

    public AuthCodeAuthenticationToken(Object principal) {
        super(null);
        this.principal= principal;
    }

    public AuthCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal= principal;
        super.setAuthenticated(true);
    }



    @Override
    public Object getCredentials() {
        return null;
    }

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

    @Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException(
                    "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        }

        super.setAuthenticated(false);
    }
}
AuthCodeAuthenticationProvider.java
package com.ruoyi.framework;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

public class AuthCodeAuthenticationProvider implements AuthenticationProvider {

    private UserDetailsService userDetailsService;

    public AuthCodeAuthenticationProvider(UserDetailsService userDetailsService) {
        setUserDetailsService(userDetailsService);
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        AuthCodeAuthenticationToken authCodeAuthenticationToken = (AuthCodeAuthenticationToken) authentication;
        String telephone = (String) authentication.getPrincipal();
        UserDetails userDetails = userDetailsService.loadUserByUsername(telephone);
        AuthCodeAuthenticationToken authenticationResult = new AuthCodeAuthenticationToken(userDetails, userDetails.getAuthorities());
        authenticationResult.setDetails(authentication.getDetails());
        return authenticationResult;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return AuthCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public UserDetailsService getUserDetailsService() {
        return userDetailsService;
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
}
在这里还要重写UserDetailsServiceByAuthCodeImpl.java原逻辑是调用的UserDetailsServiceImpl.java中的loadUserByUsername方法。
package com.ruoyi.framework.web.service;

import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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;

@Slf4j
@Service("userDetailsByAuthCode")
public class UserDetailsServiceByAuthCodeImpl implements UserDetailsService {

    @Autowired
    private ISysUserService userService;

    @Autowired
    private SysPermissionService permissionService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
    {
        SysUser user = userService.selectUserByUserName(username);
        if (StringUtils.isNull(user))
        {
            log.info("登录用户:{} 不存在.", username);
            throw new ServiceException(MessageUtils.message("user.not.exists"));
        }
        else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
        {
            log.info("登录用户:{} 已被删除.", username);
            throw new ServiceException(MessageUtils.message("user.password.delete"));
        }
        else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
        {
            log.info("登录用户:{} 已被停用.", username);
            throw new ServiceException(MessageUtils.message("user.blocked"));
        }
        return createLoginUser(user);
    }

    public UserDetails createLoginUser(SysUser user)
    {
        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
    }
}

在SecurityConfig.java中配置自定义的登录逻辑(顶部注入,下面增加配置)

配置中api开头的接口,该放开(登录获取token的接口)的放开:

温馨提示:一定要区分原来的UserDetailsService 使用注解@Qualifier("userDetailsByAuthCode")区分,原来的也要加上,不然启动时候注入重复,原来的serviceImpl实现类也要加上,如下:

SysLoginService.java中
public String wxLogin(String userName)
    {
        // 用户验证
        Authentication authentication = null;
        try
        {
            AuthCodeAuthenticationToken authCodeAuthenticationToken = new AuthCodeAuthenticationToken(userName);
            AuthenticationContextHolder.setContext(authCodeAuthenticationToken);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authCodeAuthenticationToken);
        }
        catch (Exception e)
        {
            if (e instanceof BadCredentialsException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }
        finally
        {
            AuthenticationContextHolder.clearContext();
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());
        // 生成token
        return tokenService.createToken(loginUser);
    }

接口调用中可以如下调用了:

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自定义微信小程序登录,首先需要在小程序后台配置相应的登录信息,包括app id、app secret等。然后,可以使用Spring Security提供的OAuth2登录功能进行集成。 具体步骤如下: 1. 添加依赖 ```xml <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.1.0.RELEASE</version> </dependency> ``` 2. 配置微信小程序信息 ```yaml spring: security: oauth2: client: registration: weixin: client-id: <your-client-id> client-secret: <your-client-secret> scope: snsapi_login redirect-uri: <your-redirect-uri> client-name: weixin provider: weixin: authorization-uri: https://api.weixin.qq.com/sns/jscode2session token-uri: https://api.weixin.qq.com/cgi-bin/token user-info-uri: https://api.weixin.qq.com/cgi-bin/user/info user-name-attribute: openid ``` 3. 自定义微信小程序登录处理器 ```java @Component public class WeixinOAuth2UserService extends OAuth2UserService<OAuth2UserRequest, OAuth2User> { @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { String openid = userRequest.getAdditionalParameters().get("openid").toString(); // 根据openid获取用户信息 // ... // 构造OAuth2User对象 return new DefaultOAuth2User(Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")), user.getAttributes(), user.getNameAttributeKey()); } } ``` 4. 配置Spring Security ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private WeixinOAuth2UserService weixinOAuth2UserService; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/login/**").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/") .permitAll() .and() .oauth2Login() .loginPage("/login") .userInfoEndpoint() .userService(weixinOAuth2UserService) .and() .and() .logout() .logoutUrl("/logout") .permitAll(); } } ``` 以上就是使用Spring Security自定义微信小程序登录的简单步骤,需要注意的是,微信小程序提供的是OAuth2.0协议,所以需要使用Spring Security OAuth2集成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值