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数 | 否 | int | 1 |
| fly.security.session.maxSessionsPreventsLogin | 达到最大session时是否阻止新的登录请求,默认为false,不阻止,新的登录会将老的登录失效掉 | 否 | boolean | false |
| fly.security.session.sessionInvalidUrl | session失效时跳转的地址 | 否 | String | /login |
| fly.security.rememberme.key | '记住我' 加密 key | 否 | String | remember-me |
| fly.security.rememberme.cookieName | 记住我 cookie key, 可以设置成需要配置跨域的域名 | 否 | String | remember-me |
| fly.security.rememberme.seconds | '记住我'功能的有效时间(秒数),默认7天 | 否 | int | 604800 |
| fly.security.rememberme.alwaysRemember | 是否永远记住(如果是永远记住, 登录失效后, 会重新自动登录) | 否 | boolean | false |
| fly.security.code.image.length | 图形验证码长度 | 否 | int | 6 |
| fly.security.code.image.expireIn | 图形验证码有效时间(秒) | 否 | int | 60 |
| fly.security.code.image.url | 图形验证码需要拦截的地址,多个地址之间使用英文逗号隔开 | 否 | String | - |
| fly.security.code.sms.length | 短信验证码长度 | 否 | int | 6 |
| fly.security.code.sms.expireIn | 短信验证码有效时间(秒) | 否 | int | 6 |
| 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());
}
}
剑鸣秋朔