基于springboot的简单登录
首先我们需要使用IDEA设计一个springboot项目,然后引入相关的依赖。然后在项目的resource/templates下面创建出一个登录页,也就是项目的首页,运行起来以后,应该可以看到下面的景象
之后,我们就要进行shiro相关的操作,首先需要创建一个类,是我们自定义的一个Realm,主要完成相关的认证和授权逻辑,它需要继承shiro官方提供的AuthorizingRealml类,并实现其中的两个方法
package com.example.lclepro.Config;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class LcleRealm extends AuthorizingRealm {
//执行授权逻辑
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//执行认证逻辑
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
}
之后,我们需要创建一个Shiro的核心配置类,那就是SHiroConfig,他需要实现三个方法,分别实现,对于拦截器工厂,安全管理器,自定义Realm的加载代码如下
package com.example.lclepro.Config;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ShiroConfig {
//实现拦截器
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
//实现web安全管理器的加载
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("lcleRealm") LcleRealm realm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
//实现Realm的加载
@Bean
public LcleRealm lcleRealm(){
return new LcleRealm();
}
}
之后,我们介绍shiro中的第一个对象Subject,这个对象有对应的登入登出方法,而且相应的授权方法也是基于这个对象来进行的,下面先介绍shiro的相关认证过滤器
- anon:无需认证,任何都可以使用
- authc:必须认证才可以访问(即必须登录)
- perms:需要相关授权
- role:相应的角色
我们需要进行相应的操作,是的shiro能够完成url的拦截,这时候,我们在ShiroConfig类的拦截器工厂方法中添加代码段,使得shiro可以拦截请求,并直接放行首页访问请求和登陆验证请求,方便以后的测试
package com.example.lclepro.Config;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//实现拦截器
//@Bean注解注释在方法上,将返回的实体类交给容器处理,id是方法名
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//设置拦截成功以后,访问的页面
shiroFilterFactoryBean.setLoginUrl("/");
//拦截器Map的创建
Map<String, String> map = new HashMap<String, String>();
//针对不同的url,使用不同的拦截器,放到map中,即可生效,完成拦截
//拦截所有请求
map.put("/*", "authc");
//放行登陆请求
map.put("/", "anon");
//放行登录认证请求
map.put("/user/login", "anon");
//设置相关的map集合,完成拦截功能的收集
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//实现web安全管理器的加载
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("lcleRealm") LcleRealm realm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
//实现Realm的加载
@Bean
public LcleRealm lcleRealm(){
return new LcleRealm();
}
}
这样一来,就能实现拦截,然后普先建立一个controller用来接收登陆页面拿到的用户名和密码,然后就要开始验证方法了
package com.example.lclepro.Controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("user")
public class UserController {
@PostMapping("/login")
public ModelAndView login(@RequestParam("username") String username, @RequestParam("password") String password){
ModelAndView mv = new ModelAndView();
//获取到Subject对象
Subject suject = SecurityUtils.getSubject();
//将收集到的用户名和密码存储到token中
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//执行登入方法
try {
suject.login(token);
mv.setViewName("pages/success");
}
catch (UnknownAccountException e){
//用户名不存在时抛出的异常
mv.addObject("msg", "用户不存在,请找到合适的介绍人加入组织(๑•̀ㅂ•́)و✧");
mv.setViewName("pages/index");
}
catch (IncorrectCredentialsException e){
//用户名密码不匹配时抛出的异常
mv.addObject("msg", "用户名与密码不匹配( ̄_, ̄ )");
mv.setViewName("pages/index");
}
return mv;
}
}
在这里,我们顺一下逻辑,当我们实例化subject对象以后,调用login方法时,就睡进入到shiro的认证逻辑代码中,即doGetAuthenticationInfo方法,传入参数类型是AuthenticationToken,我们不妨使用类型强转,转化成UsernamePasswordToken类型,获取到其中的封装过的用户名和密码,再和数据库中获取用户名和密码进行比对,完成用户登陆的逻辑
package com.example.lclepro.Config;
import com.example.lclepro.Service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
public class LcleRealm extends AuthorizingRealm {
@Autowired
UserService userService;
//执行授权逻辑
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//执行认证逻辑,执行login()方法以后,会进入到这里,进行用户名密码的比对
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//执行认证逻辑
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//获取密码
String password = userService.isUser(token.getUsername());
if(password==null){
throw new UnknownAccountException();
}
return new SimpleAuthenticationInfo("", password, "");
}
}
今天的工作告一段落,简单的登录实现了,希望这场瘟疫早些过去,生活回到正轨