Skip to content
章节导航

Spring Security 登录认证

依赖引入

xml
<dependency>
    <groupId>com.github.itdachen</groupId>
    <artifactId>security-spring-boot-starter</artifactId>
    <version>[最新版本]</version>
</dependency>

配置文件

配置示例

yaml
fly:
  # 安全认证配置
  security:
    signInPage: /login # 登录页面地址
    signOutUrl: /login # 退出登录成功之后跳转地址
    successForwardUrl: /index # 登录成功后跳转地址
    session:
      sessionInvalidUrl: /login # 登录失效后跳转地址
    matchers: # 不需要登录认证拦截地址
      - /open/**

编写 WebSecurityConfigurerAdapter

编写配置类,继承 WebSecurityConfigurerAdapter 类,WebSecurityConfigurerAdapter 类默认集成了网页登录以及短信登录,案例如下:

java
import com.github.itdachen.boot.security.config.WebSecurityConfigurerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;


@Configuration
@EnableWebSecurity
@EnableMethodSecurity(proxyTargetClass = true)
public class FlyNextWebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    /***
     * WebSecurityConfigurerAdapter 被弃用
     * 替代方案: 申明 SecurityFilterChain 的 Bean
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        /**
         * 默认集成安全认证, 可重写 WebSecurityConfigurerAdapter 类中的方法
         */
        configure(http);

        return http.build();
    }

}

若默认登录方式无法满足当前环境, 可以重写 WebSecurityConfigurerAdapter 类中 httpSecurityApply() 方法。

查询用户以及权限

查询用户信息,需要继承 AbstractSecurityUserDetailsService 类,重写类中的 loadUserByUsername 方法查询用户信息,重写 getUserAuthority 方法获取用户权限信息,实例 :

java
import com.github.itdachen.auth.manager.IUserMenuManager;
import com.github.itdachen.auth.mapper.IAuthenticationAuthorityMapper;
import com.github.itdachen.auth.mapper.IUserDetailsMapper;
import com.github.itdachen.boot.autoconfigure.app.AppInfoProperties;
import com.github.itdachen.boot.autoconfigure.app.PlatformInfoProperties;
import com.github.itdachen.boot.security.constants.LoginModeConstant;
import com.github.itdachen.boot.security.details.AbstractSecurityUserDetailsService;
import com.github.itdachen.boot.security.exception.BizSecurityException;
import com.github.itdachen.boot.security.user.CurrentUserInfo;
import com.github.itdachen.framework.context.constants.YesOrNotConstant;
import com.github.itdachen.framework.context.userdetails.UserInfoDetails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;


@Service
public class AdminSecurityUserDetailsService extends AbstractSecurityUserDetailsService {
    private static final Logger logger = LoggerFactory.getLogger(AdminSecurityUserDetailsService.class);


    /** 根据登录账号查询用户信息 */
    @Override
    public CurrentUserInfo loadUserByUsername(String username) throws UsernameNotFoundException {
        /* 查询用户信息 */
        UserInfoDetails user = userDetailsMapper.loadUserByUsername(username);
        if (null == user) {
            logger.error("登录账号: " + username + " 不存在");
            throw new BizSecurityException("登录账号 " + username + " 不存在,请检查账号是否正确");
        }
        /* ... 登录其他信息除了 */

        return toVerifyUserDetails(user);
    }

    /** 根据电话号码查询用户信息 */
    @Override
    public CurrentUserInfo loadUserByMobile(String mobile) throws UsernameNotFoundException {
        /* 查询用户信息 */
        UserInfoDetails user = userDetailsMapper.loadUserByMobile(mobile);
        if (null == user) {
            logger.error("登录手机号: " + mobile + " 不存在");
            throw new BizSecurityException("登登录手机号录账号 " + mobile + " 不存在,请检查手机号是否正确!!!");
        }
        /* ... 登录其他信息除了 */

        return toVerifyUserDetails(user);
    }


    /** 获取权限信息 */
    @Override
    protected Set<String> getUserAuthority(UserInfoDetails userInfoDetails) {
        /* 查询用户权限 */
        List<String> userAuthority = authenticationAuthorityMapper.findUserAuthority(userInfoDetails.getAppId(), list);
        return new HashSet<>(userAuthority);
    }

}

其他配置

类型描述必填数据类型默认值
fly.security.signInPage登录页面String-
fly.security.logout退出登录地址String/logout
fly.security.signOutUrl退出登录成功之后跳转地址String/login
fly.security.successForwardUrl登录成功之后跳转地址String/
fly.security.matchers不需要登录认证就能访问的地址List/
fly.security.session.maximumSessions同一个用户在系统中的最大session数int1
fly.security.session.maxSessionsPreventsLogin达到最大session时是否阻止新的登录请求,默认为false,不阻止,新的登录会将老的登录失效掉booleanfalse
fly.security.session.sessionInvalidUrlsession失效时跳转的地址String/login
fly.security.rememberme.key'记住我' 加密 keyStringremember-me
fly.security.rememberme.cookieName记住我 cookie key, 可以设置成需要配置跨域的域名Stringremember-me
fly.security.rememberme.seconds'记住我'功能的有效时间(秒数),默认7天int604800
fly.security.rememberme.alwaysRemember是否永远记住(如果是永远记住, 登录失效后, 会重新自动登录)booleanfalse
fly.security.code.image.length图形验证码长度int6
fly.security.code.image.expireIn图形验证码有效时间(秒)int60
fly.security.code.image.url图形验证码需要拦截的地址,多个地址之间使用英文逗号隔开String-
fly.security.code.sms.length短信验证码长度int6
fly.security.code.sms.expireIn短信验证码有效时间(秒)int6
fly.security.code.sms.url短信验证码需要拦截的地址,多个地址之间使用英文逗号隔开String-

短信验证码发送接口

短信验证码默认打印在控制台,实际开发中需要实现 SmsCodeSender 接口,根据自己开发情况选择短信发送服务器。

java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.github.itdachen.boot.security.validate.code.sms.SmsCodeSender;


@Component
public class DefaultSmsCodeSender implements SmsCodeSender {
    private static final Logger logger = LoggerFactory.getLogger(DefaultSmsCodeSender.class);

    @Override
    public void send(String mobile, String code) {
        logger.info("向手机 " + mobile + " 发送短信验证码: " + code);
        // 短信发送具体实现 ...
    }

}

获取登录用户信息

全局获取

  • 获取登录用户详细信息
shell
UserInfoDetails userDetails = BizContextHandler.getUserDetails();
  • 获取用户某一属性信息
方法名称描述
BizContextHandler.getUserId()获取用户ID
BizContextHandler.getNickName()获取昵称/姓名
BizContextHandler.getUsername()获取登录账号
BizContextHandler.getTenantId()获取租户 ID/公司 ID
BizContextHandler.getTenantTitle()获取 租户名称/公司名称
BizContextHandler.getPlatId()获取平台 ID
BizContextHandler.getPlatName()获取平台名称
BizContextHandler.getAppId()获取应用 ID
BizContextHandler.getAppName()获取应用名称
BizContextHandler.getAppVersion()获取应用应用版本号
BizContextHandler.getAvatar()获取头像
BizContextHandler.getEmail()获取电子邮箱
BizContextHandler.getSex()获取性别
BizContextHandler.getUserType()获取用户类型
BizContextHandler.getTelephone()获取电话号码
BizContextHandler.getRoleId()获取身份 ID/身份代码
BizContextHandler.getRoleName()获取身份名称
BizContextHandler.getRoleFlag()获取主身份标识
BizContextHandler.getDeptId()获取部门代码
BizContextHandler.getDeptTitle()获取部门名称
BizContextHandler.getDeptParentId()获取上级部门代码
BizContextHandler.getDeptLevel()获取部门等级
BizContextHandler.getProvCode()获取身份所属省份代码
BizContextHandler.getProvName()获取身份所属省份名称
BizContextHandler.getCityCode()获取身份所属市州代码
BizContextHandler.getCityName()获取身份所属市州名称
BizContextHandler.getCountyCode()获取身份所属区县代码
BizContextHandler.getCountyName()获取身份所属区县名称

获取更多用户信息,查看 com.github.itdachen.framework.context.BizContextHandler 类。更多信息,需要在登录时添加到登录用户信息中。

注解获取

通过自定义解析器的方式,实现注解获取用户信息。

  • 编写 WebMvcConfigurer.addArgumentResolvers
java
import com.github.itdachen.boot.security.interceptor.FlyWebSecurityInterceptor;
import com.github.itdachen.boot.security.matchers.IAuthorizeRequestMatchers;
import com.github.itdachen.boot.security.resolvers.FlyUserDetailsMethodArgumentResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;


/**
 * web 配置
 */
@Configuration
public class FlyNextWebMvcConfigurer implements WebMvcConfigurer {
    private static final Logger logger = LoggerFactory.getLogger(FlyNextWebMvcConfigurer.class);


    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(currentUserMethodArgumentResolver());
    }

    /* 自定义解析器,用于获取登录用户信息 */
    @Bean
    public FlyUserDetailsMethodArgumentResolver currentUserMethodArgumentResolver() {
        return new FlyUserDetailsMethodArgumentResolver();
    }


}
  • controller 层,添加 @CurrentUser 注解。
java
import com.github.itdachen.framework.context.annotation.CurrentUser;
import com.github.itdachen.framework.context.userdetails.UserInfoDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * 通过注解的方式获取当前登录用户信息
 */
@Controller
public class DashboardController {


    @GetMapping("/user")
    public void home(@CurrentUser UserInfoDetails userInfoDetails) throws Exception {
        System.out.println(userInfoDetails.toString());
    }


}