SpringBoot 整合 Shiro 密码登录与邮件验证码登录功能(多 Realm 认证)
导入依赖(pom.xml)
org.apache.shiro shiro-spring 1.4.0 com.auth0 java-jwt 3.2.0
在SpringBoot项目配置config包下创建ShiroConfig配置类
@Configuration
publicclassShiroConfig{
/**
*ShiroFilterFactoryBean
*
*anon:无需认证就可以访问
*authc:必须认证才能访问
*user:必须拥有记住我功能才能用
*perms:拥有对某个资源的权限能访问
*role:拥有某个角色权限能访问
*/
@Bean
publicShiroFilterFactoryBeangetShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManagerdefaultWebSecurityManager){
ShiroFilterFactoryBeanfactoryBean=newShiroFilterFactoryBean();
//设置安全管理器
factoryBean.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
MapfilterMap=newLinkedHashMap<>();
//放行不需要权限认证的接口
//网站首页
filterMap.put("/","anon");
filterMap.put("/index","anon");
filterMap.put("/index.html","anon");
//不验证跳转接口
filterMap.put("/into/**","anon");
//需要权限认证的接口
//验证跳转接口
filterMap.put("/verifyInto/**","authc");
factoryBean.setFilterChainDefinitionMap(filterMap);
//访问没有授权的资源
factoryBean.setLoginUrl("redirect:/into/login");
//设置无权限时跳转的url
factoryBean.setUnauthorizedUrl("redirect:/into/login");
returnfactoryBean;
}
/**
*管理shiro的生命周期
*/
@Bean("lifecycleBeanPostProcessor")
publicLifecycleBeanPostProcessorlifecycleBeanPostProcessor(){
returnnewLifecycleBeanPostProcessor();
}
/**
*注入密码登录CustomRealm
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
publicUserPasswordRealmuserPasswordRealm(){
returnnewUserPasswordRealm();
}
/**
*注入邮箱验证登录EmailRealm
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
publicUserEmailRealmuserEmailRealm(){
returnnewUserEmailRealm();
}
/**
*默认安全管理器
*/
@Bean
publicDefaultWebSecurityManagersecurityManager(UserPasswordRealmuserPasswordRealm,UserEmailRealmuserEmailRealm,AbstractAuthenticatorabstractAuthenticator){
DefaultWebSecurityManagerdefaultWebSecurityManager=newDefaultWebSecurityManager();
Listrealms=newArrayList<>();
realms.add(userPasswordRealm);
realms.add(userEmailRealm);
defaultWebSecurityManager.setRealms(realms);
//记住我
defaultWebSecurityManager.setRememberMeManager(cookieRememberMeManager());
defaultWebSecurityManager.setAuthenticator(abstractAuthenticator);
returndefaultWebSecurityManager;
}
/**
*认证器把我们的自定义验证加入到认证器中
*/
@Bean
publicAbstractAuthenticatorabstractAuthenticator(UserPasswordRealmuserPasswordRealm,UserEmailRealmuserEmailRealm){
//自定义模块化认证器,用于解决多realm抛出异常问题
//开始没用自定义异常问题,发现不管是账号密码错误还是什么错误
//shiro只会抛出一个AuthenticationException异常
ModularRealmAuthenticatorauthenticator=newMyCustomModularRealmAuthenticator();
//认证策略:AtLeastOneSuccessfulStrategy(默认),AllSuccessfulStrategy,FirstSuccessfulStrategy
authenticator.setAuthenticationStrategy(newAtLeastOneSuccessfulStrategy());
//加入realms
Listrealms=newArrayList<>();
realms.add(userPasswordRealm);
realms.add(userEmailRealm);
authenticator.setRealms(realms);
returnauthenticator;
}
/**
*加入shiro注解代理生成器切面
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
publicDefaultAdvisorAutoProxyCreatoradvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreatoradvisorAutoProxyCreator=newDefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
returnadvisorAutoProxyCreator;
}
/**
*加入shiro注解切点
*/
@Bean
publicAuthorizationAttributeSourceAdvisorauthorizationAttributeSourceAdvisor(DefaultWebSecurityManagersecurityManager){
AuthorizationAttributeSourceAdvisorauthorizationAttributeSourceAdvisor=newAuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
returnauthorizationAttributeSourceAdvisor;
}
/**
*设置cookie记住我生成cookie
*/
@Bean
publicCookieRememberMeManagercookieRememberMeManager(){
CookieRememberMeManagercookieRememberMeManager=newCookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
returncookieRememberMeManager;
}
/**
*设置cookie有效时间
*/
@Bean
publicSimpleCookierememberMeCookie(){
/*这个参数是cookie的名称,对应前端页面的checkbox的name=remremberMe*/
SimpleCookiesimpleCookie=newSimpleCookie("rememberMe");
/*cookie的有效时间为30天,单位秒*/
simpleCookie.setMaxAge(259200);
returnsimpleCookie;
}
}
创建自定义验证器MyCustomModularRealmAuthenticator类
publicclassMyCustomModularRealmAuthenticatorextendsModularRealmAuthenticator{
@Override
protectedAuthenticationInfodoMultiRealmAuthentication(Collectionrealms,AuthenticationTokentoken){
AuthenticationStrategyauthenticationStrategy=this.getAuthenticationStrategy();
AuthenticationInfoauthenticationInfo=authenticationStrategy.beforeAllAttempts(realms,token);
Iteratorvar5=realms.iterator();
while(var5.hasNext()){
Realmrealm=(Realm)var5.next();
authenticationInfo=authenticationStrategy.beforeAttempt(realm,token,authenticationInfo);
if(realm.supports(token)){
AuthenticationInfoinfo=null;
Throwablet=null;
info=realm.getAuthenticationInfo(token);
authenticationInfo=authenticationStrategy.afterAttempt(realm,token,info,authenticationInfo,t);
}
}
authenticationInfo=authenticationStrategy.afterAllAttempts(token,authenticationInfo);
returnauthenticationInfo;
}
}
创建密码登录时验证授权UserPasswordRealm类
@Component
publicclassUserPasswordRealmextendsAuthorizingRealm{
//注入用户业务
@Autowired
privateUserMapperuserMapper;
/**
*授权
*/
@Override
protectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipals){
System.out.println("————密码授权————doGetAuthorizationInfo————");
returnnull;
}
/**
*认证
*/
@Override
protectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokentoken)throwsAuthenticationException{
System.out.println("————密码认证————doGetAuthenticationInfo————");
UsernamePasswordTokenuserToken=(UsernamePasswordToken)token;
//连接数据库查询用户数据
QueryWrapperwrapper=newQueryWrapper<>();
wrapper.eq("user_name",userToken.getUsername());
Useruser=userMapper.selectOne(wrapper);
//验证用户
if(user==null){
thrownewUnknownAccountException();
}
returnnewSimpleAuthenticationInfo("",user.getUserPassword(),"");
}
/**
*用来判断是否使用当前的realm
*
*@paramvar1传入的token
*@returntrue就使用,false就不使用
*/
@Override
publicbooleansupports(AuthenticationTokenvar1){
returnvar1instanceofUsernamePasswordToken;
}
}
创建邮件验证码登录时验证授权UserEmailRealm类
@Component
publicclassUserEmailRealmextendsAuthorizingRealm{
//注入用户业务
@Autowired
UserServiceuserService;
@Override
protectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipalCollection){
System.out.println("————邮箱登录授权————doGetAuthorizationInfo————");
returnnull;
}
@Override
protectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokentoken)throwsAuthenticationException{
System.out.println("————邮箱登录认证————doGetAuthenticationInfo————");
UserEmailTokenuserEmailToken=(UserEmailToken)token;
StringuserEmail=(String)userEmailToken.getPrincipal();
//连接数据库查询用户数据
QueryWrapperwrapper=newQueryWrapper<>();
wrapper.eq("user_email",userEmail);
Useruser=userService.getOne(wrapper);
//因为没有密码,并且验证码在之前就验证了
if(user==null){
thrownewUnknownAccountException();
}
returnnewSimpleAuthenticationInfo("",userEmail,"");
}
/**
*用来判断是否使用当前的realm
*
*@paramvar1传入的token
*@returntrue就使用,false就不使用
*/
@Override
publicbooleansupports(AuthenticationTokenvar1){
returnvar1instanceofUserEmailToken;
}
}
创建邮件验证码登录验证通过生成令牌的UserEmailToken类(密码登录时使用shiro默认的UsernamePasswordToken令牌)
@Data//使用lombok生成get方法、set方法
publicclassUserEmailTokenimplementsHostAuthenticationToken,RememberMeAuthenticationToken{
privateStringuserEmail;
privatebooleanrememberMe;
privateStringhost;
publicUserEmailToken(){
this.rememberMe=false;
}
publicUserEmailToken(StringuserEmail){
this(userEmail,false,null);
}
publicUserEmailToken(StringuserEmail,booleanrememberMe){
this(userEmail,rememberMe,null);
}
publicUserEmailToken(StringuserEmail,booleanrememberMe,Stringhost){
this.userEmail=userEmail;
this.rememberMe=rememberMe;
this.host=host;
}
@Override
publicStringgetHost(){
returnhost;
}
@Override
publicbooleanisRememberMe(){
returnrememberMe;
}
/**
*重写getPrincipal方法
*/
@Override
publicObjectgetPrincipal(){
returnuserEmail;
}
/**
*重写getCredentials方法
*/
@Override
publicObjectgetCredentials(){
returnuserEmail;
}
}
创建密码盐值加密MDPasswordUtil工具类
publicclassMDPasswordUtil{
publicStringgetMDPasswordUtil(StringuserName,StringuserPassword){
StringhashAlgorithmName="MD5";//加密方式:md5加密
Objectcredentials=userPassword;//密码
Objectsalt=ByteSource.Util.bytes(userName);//盐
inthashIterations=512;//加密次数
Objectresult=newSimpleHash(hashAlgorithmName,credentials,salt,hashIterations);
returnresult.toString();
}
}
控制层用户密码登录
//用户密码登录
@PostMapping("/passwordLogin")
publicStringuserLogin(@RequestParam("userName")StringuserName,
@RequestParam("userPassword")StringuserPassword,
HttpSessionsession,Modelmodel){
//获取当前的用户
Subjectsubject=SecurityUtils.getSubject();
//对密码进行MD5盐值加密
Stringmd5Password=newMDPasswordUtil().getMDPasswordUtil(userName,userPassword);
//封装用户的登录数据
UsernamePasswordTokentoken=newUsernamePasswordToken(userName,md5Password);
//rememberme记住我
token.setRememberMe(true);
try{
//登录,验证,保存令牌
subject.login(token);
//查询登录信息
QueryWrapperwrapper=newQueryWrapper<>();
wrapper.eq("user_name",userName);
Useruser=userService.getOne(wrapper);
//保存登录用户信息
session.setAttribute(user.getUserId().toString(),user);
return"admin";
}catch(UnknownAccountExceptione){
model.addAttribute("userError","用户名错误!请重新输入。");
return"login";
}catch(IncorrectCredentialsExceptionice){
model.addAttribute("pwError","密码错误!请重新输入。");
return"login";
}
}
控制层用户邮件验证码密码登录
//用户邮箱登录
@PostMapping("/emailLogin")
publicStringemailLogin(@RequestParam("userEmail")StringuserEmail,
@RequestParam("emailCode")StringemailCode,
HttpSessionsession,Modelmodel){
//根据userEmail从session中取出发送的验证码
StringsendEmailCode=(String)session.getAttribute(userEmail);
//比对验证码
if(StringUtils.isNoneBlank(sendEmailCode)&&sendEmailCode.equals(emailCode)){
try{
UserEmailTokentoken=newUserEmailToken(userEmail);
//rememberme记住我
token.setRememberMe(true);
//登录,验证,保存令牌
Subjectsubject=SecurityUtils.getSubject();
subject.login(token);
//查询登录信息
QueryWrapperwrapper=newQueryWrapper<>();
wrapper.eq("user_email",userEmail);
Useruser=userService.getOne(wrapper);
//保存登录用户信息
session.setAttribute(user.getUserId().toString(),user);
//销毁验证码
session.removeAttribute(emailCode);
return"admin";
}catch(Exceptione){
model.addAttribute("error","验证码错误!请重新输入。");
return"login";
}
}else{
return"login";
}
}
SpringBoot整合Shiro密码登录与邮件验证码登录(多Realm认证)就可以了(有点多,哈哈哈)
推荐大神:狂神说Java
到此这篇关于SpringBoot整合Shiro密码登录与邮件验证码登录(多Realm认证)的文章就介绍到这了,更多相关SpringBoot整合Shiro登录内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。