jsp登录功能的实现_SpringBoot Shiro 实现登录/记住我的功能

导读

Apache Shiro 是一个简单且强大的框架。 提供了全面的安全管理服务、认证、授权、加密和会话管理等功能,相对于其他安全框架,Shiro 使用简单,上手快,也是受到了很多企业的青睐。本教程会使用Springboot + Shiro + mybatis-plus +thymeleaf+lombok实现开发流程。

创建一个hsb-admin项目

依赖包

org.springframework.boot        spring-boot-starter-parent        2.2.6.RELEASE3.3.21.1.22org.projectlombok            lombok            truecom.alibaba                druid-spring-boot-starter                ${druid-spring-boot-starter.version}com.baomidou                mybatis-plus-boot-starter                ${mybatis-plus-boot-starter.version}org.springframework.boot  spring-boot-starter-web  org.springframework.boot            spring-boot-starter-thymeleaf    mysqlmysql-connector-javaorg.apache.shiro    shiro-spring-boot-starter    1.6.0com.github.theborakompanionithymeleaf-extras-shiro2.0.0

编辑application.yml配置

server:  port: 7010spring:  application:    # 服务名,在注册时所用,调用方所用     name: hsb-admin  mvc:    #静态目录配置    static-path-pattern: /static/**   datasource:    type: com.alibaba.druid.pool.DruidDataSource    driver-class-name: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://192.168.0.103:3306/hsb?serverTimezone=UTC&useUnicode=true&zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8&autoReconnect=true&&useSSL=false    username: root    password: 123456        druid:       #初始化链接数大小      initial-size: 5      #最大链接数大小      max-active: 50      #空闲链接数大小      min-idle: 2      #链接超时时间,单位ms      max-wait: 50000  thymeleaf:    cache: falsemybatis-plus:  configuration:    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

新建HsbAdminApp启动程序

/** * 后台项目 */@SpringBootApplication(scanBasePackages = "com.hsb")@MapperScan(basePackages = "com.hsb.admin.dao")//指定扫描dao接口public class HsbAdminApp {    public static void main( String[] args )    {        SpringApplication.run(HsbAdminApp.class, args);    }    }

新建SysUserPO

该类就是用户登录PO类

@Data@EqualsAndHashCode(callSuper = false)@TableName("sys_user")public class SysUserPO implements Serializable {    private static final long serialVersionUID=1L;        Long id;//主键ID',    String username;//'用户名',    String password;//'密码',    Integer status;//'状态:0禁用,1启用',    Date createTime;//'创建时间',    Date updateTime;//'更新时间',    Long createrId;//'创建者',}

新建SysUserDAO/SysUserService这两个类大家自行创建,里面都是新增改查逻辑,部分代码如下

/** * 基础Dao,所有Dao都要继承该类 */public interface BaseDAO extends BaseMapper,Mapper{}/** * 系统用户账号  DAO */public interface SysUserDAO extends BaseDAO {}
/** * 系统用户业务 Service */@Servicepublic class SysUserService {@AutowiredSysUserDAO sysUserDAO;/** *   获取对象 * @param sysUserPO * @return */public SysUserPO get(SysUserPO sysUserPO) {//查询返回用户QueryWrapper queryWrapper=new QueryWrapper(sysUserPO);return sysUserDAO.selectOne(queryWrapper);}}

新建LoginController

该负责用Shiro执行登录,登录错误提示,登录成功逻辑

/** * 登录控制器 */@Controller@Slf4jpublic class LoginController {/** * 登录页面 * @return */@GetMapping("login")public String login() {return "login";}/** * 执行登录 * @param loginReqVO * @return */@PostMapping("login")@ResponseBodypublic ResponseVO> login(LoginReqVO loginReqVO){try {log.info("登录信息={}",loginReqVO);//shiro 从安全工具类,获取一个Subject,代表了当前 “用户”//所有 Subject 都绑定到 SecurityManager,与 Subject 的所有交互都会委托给 SecurityManagerSubject subject = SecurityUtils.getSubject();//创建一个认证凭证,且这个认证凭证是用户名,密码转入到shiro执行登录认证UsernamePasswordToken authenticationToken=new UsernamePasswordToken(loginReqVO.getUsername(), loginReqVO.getPassword());//是否记住登录authenticationToken.setRememberMe(loginReqVO.isRememberMe());//执行登录subject.login(authenticationToken);//代码走到这里,说明登录成功了SysUserPO sysUserPO=(SysUserPO)subject.getPrincipal();log.info("登录成功,从shrio获取到已成功用户对象信息={}",sysUserPO);}catch (UnknownAccountException e) {//不存在账号抛出异常log.error(e.getMessage());;return ResponseVO.fail("用户不存在");}catch (DisabledAccountException e) {//账号被禁用log.error(e.getMessage());;return ResponseVO.fail("用户被禁用,请联系管理员");}catch (IncorrectCredentialsException e) {//异常说明,不正确的凭证,意思就是密码错误log.error(e.getMessage());;return ResponseVO.fail("密码错误");}catch (RuntimeException e) {//运行时,自定义抛出异常log.error("自定义错误异常",e);return ResponseVO.fail(e.getMessage());}return ResponseVO.success(null);}/** *  退出登录 * @return */@GetMapping("loginout")public String loginout() {Subject subject=SecurityUtils.getSubject();SysUserPO sysUserPO=(SysUserPO)subject.getPrincipal();subject.logout();log.info("退出登录={}",sysUserPO.getUsername());return "login";}}

新建SysUserRealm类

/** * Realm域,Shiro 从从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份
* 1、那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法
* 2、需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作
*/@Slf4j@Configuration public class SysUserRealm extends AuthenticatingRealm{@AutowiredSysUserService sysUserService;/** * 身份认证 / 登录,验证用户是不是拥有相应的身份
* SecurityUtils.getSubject().login()执行后--->进入这个方法执行具体登录校验
* */@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//得到用户密码token凭证UsernamePasswordToken usernamePasswordToken=(UsernamePasswordToken)token;//获得登录用户名,密码String userName=usernamePasswordToken.getUsername();log.info("登录授权,username={}",userName);//根据用户名查询用户对象SysUserPO sysUserPO=new SysUserPO();sysUserPO.setUsername(userName);sysUserPO=sysUserService.get(sysUserPO);//如果等于null,说明用户不存在。//问题如何返回用户提示不存在呢?if(sysUserPO==null) {//通过抛出异常来解决提示错误信息throw new UnknownAccountException("用户不存在=".concat(userName));//自定义抛出异常,如果不是AuthenticationException子类,那么异常信息不会向上抛出,因此自定义异常要继承这个类,Shiro提供的默认异常基本够用了//throw new RuntimeException("用户不存在");}//如果账号状态是禁用状态if(new Integer(0).equals(sysUserPO.getStatus())){throw new DisabledAccountException("用户被禁用=".concat(userName));}//账号正常,校验登录密码//第一个参数,存返回用户对象,第二个参数存密码,第三个登录用户名SimpleAuthenticationInfo simpleAuthenticationInfo=new SimpleAuthenticationInfo(sysUserPO, sysUserPO.getPassword(), sysUserPO.getUsername());//返回登录授权信息,shiro会自动校验转入的密码与数据库返回的密码是否一致,如果一致,代表登录成功return simpleAuthenticationInfo;}}

新建ShiroConfig类

/** * Shiro配置类
* 该类主要初始化启动装载Shiro类对象,完成相关实例化工作,为后面功能提供服务 */@Configurationpublic class ShiroConfig { /** * 实例化一个Shiro安全管理器,相当于 SpringMVC 中的 DispatcherServlet
* 所有具体的交互都通过 SecurityManager 进行控制;它管理着所有 Subject、且负责进行认证和授权、及会话、缓存的管理
* @param userRealm 注入用户认证,权限安全域 * @return */ @Bean public DefaultWebSecurityManager securityManager(SysUserRealm userRealm) { DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager(); //设置用户域 defaultSecurityManager.setRealm(userRealm); //设置记住密码管理 defaultSecurityManager.setRememberMeManager(cookieRememberMeManager()); //创建了一个session管理器 defaultSecurityManager.setSessionManager(defaultWebSessionManager()); ThreadContext.bind(defaultSecurityManager);//解决异常:ThreadContext or as a vm static singleton return defaultSecurityManager; } /** * 配置shiro过滤器后,相当于servlet的filter
* 1、页面才能正常使用shiro相关标签,不然使用无效,如< shiro:principal property="username"/>
* 2、其他类获取SysUserPO sysUserPO=(SysUserPO)SecurityUtils.getSubject().getPrincipal();才不会报错
* @param securityManager * @return */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) { //创建一个过滤工厂Bean,跟我们以前web用的过滤器类似 ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //注入安全管理类 shiroFilterFactoryBean.setSecurityManager(securityManager); //设置登录页面路径 shiroFilterFactoryBean.setLoginUrl("/login"); //设置没有权限访问进入路径 shiroFilterFactoryBean.setUnauthorizedUrl("/notAuth"); //创建一个过滤路径map对象,key是路径,value值说明:anon代表匿名访问,authc代表必须登录subject.login认证后授权后才能访问 Map filterChainDefinitionMap = new LinkedHashMap<>(); //放开static静态文件路径不授权就可以访问,如果不放开,相关js,css将无法访问 filterChainDefinitionMap.put("/static/**", "anon"); //放开执行登录操作 filterChainDefinitionMap.put("/login", "anon"); //退出登录操作 filterChainDefinitionMap.put("/loginout", "logout"); //authc其他所有路径都必须通过subject.login认证后才能访问 //filterChainDefinitionMap.put("/**", "authc"); //如果用了rememberMe记住我功能,那就必须把authc改成user,否则记住我功能失效,必须要记住了 filterChainDefinitionMap.put("/**", "user"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /** * Shiro 整合thymeleaf框架,加这个注解后才能使用标签,如
* < shiro:principal property="username"/>
* @return */ @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } //<===============RememberMe配置==================> /** * Cookie记住我管理器 * @return */ @Bean public RememberMeManager cookieRememberMeManager() { CookieRememberMeManager cookieRememberMeManager=new CookieRememberMeManager(); //rememberMe cookie加密的密钥 默认AES算法 密钥长度(128 256 512 位) //6BvVHd5gUs0FEA86DFAdAg== 是密码钥匙,建议每个项目都不一样 cookieRememberMeManager.setCipherKey(Base64.decode("6BvVHd5gUs0FEA86DFAdAg==")); //设置cookie cookieRememberMeManager.setCookie(simpleCookie()); return cookieRememberMeManager; } /** * 自定义指定cookie多少天,如果没有操作的情况下自动过期 * @return */@Beanpublic SimpleCookie simpleCookie() { //创建一个cookie名称 SimpleCookie simpleCookie=new SimpleCookie("rememberMe"); simpleCookie.setMaxAge(2592000);//单位秒,折算成30天 return simpleCookie; } /** * 创建一个session管理器,解决重定向自动带有;jsessionid=0935FAEB578E70CDB29AA08303F91C69 * @return */ @Bean public DefaultWebSessionManager defaultWebSessionManager() { DefaultWebSessionManager defaultWebSessionManager=new DefaultWebSessionManager(); //移除重定向不自动带有;jsessionid=0935FAEB578E70CDB29AA08303F91C69功能 defaultWebSessionManager.setSessionIdUrlRewritingEnabled(false); return defaultWebSessionManager; }}

新建登录页面

登录login.html页面,登录成功后进入后台主页,没有登录,无法进入主页

    有贝口腔网-登录            登录来到后台登录页面
账号:
密码:
记住我:

新建后台IndexController

/** * 后台主页 */@Controller@Slf4jpublic class IndexController {/** *   进入首页页面 * @return */@GetMapping("/")public String add() { //测试从shiro获取登录用户信息 SysUserPO sysUserPO=(SysUserPO)SecurityUtils.getSubject().getPrincipal(); log.info("进入主页,获取到登录用户信息={}",sysUserPO);return "index";}}

主页index.html页面

管理主页欢迎来到后台管理系统
您好: 退出登录

系统用户管理
注意说明: 标签显示登录用户名;(1)他是等价于:String username=((SysUserPO)SecurityUtils.getSubject().getPrincipal()).getUsername();//获取这个值(2)filterChainDefinitionMap.put("/**", "user"); //一定要过滤器配置"/** "拦截所有路径,才能显示生效

登录代码流程

3988c6b4ab5f6a8bd73734f84483ef2c.png

shiro登录代码流程

启动服务

测试访问, 这样就可以实现了用Shiro登录功能了。

测试一:不登录,直接访问主页,那么系统就会自动跳转到登录页面http://127.0.0.1:7010/测试二:登录页面,登录后进入主页,主页显示登录用户名http://127.0.0.1:7010/login    测试三:测试登录记住我功能,看下面流程

RememberMe记住我

RememberMe记住我是Shiro 提供的一项功能,比如访问某些网站时,关闭了浏览器下次再打开时还是能记住你是谁,下次访问时无需再登录即可访问。如果是浏览器登录,一般会把 RememberMe 的 Cookie 写到客户端并保存下来。

1、登录LoginController设置记住代码

80671f0cca8fa88941f84fe96f13a3a5.png

记住用户代码

2、配置ShiroConfig

(1)配置RememberMeManager记住管理器,注意加密秘钥key,用到的AES对着加密技术实现(2)配置SimpleCookie自定义记住有效天数(3)修改ShiroFilterFactoryBean过滤权限,要使用user不要使用authc,具体说明看代码说明
ddf2d1a72eb3aaa19a046199555ea0ca.png

记住管理器

a4c71a0af476cadf8dff2f16e248cc22.png

设置记住管理器

4c490060c79e116fa00a7e36bd513890.png

很重要的一个配置

3、最后重启服务,测试记住我功能,不管你关闭浏览器或者重启服务,再次直接访问页面都是可以直接访问了,不需要进入登录页面。

登录页面jsessionid问题

如果你测试记住我公,出现如下登录页面异常

http://127.0.0.1:7010/login;jsessionid=0935FAEB578E70CDB29AA08303F91C69页面显示如下This application has no explicit mapping for /error, so you are seeing this as a fallback.Thu Nov 19 19:58:43 CST 2020There was an unexpected error (type=Bad Request, status=400).Invalid request

解决方式加入DefaultWebSessionManager如下图

0ea8c50227437cff456faf113bace3e5.png

创建session管理器,移除重定向

970ff0b7dd9547f779b2e4f85893021c.png

设置DefaultWebSessionManager

总结

本教程讲解了springboot+shiro实现登录,记住我功能,很简单地实现了这些功能。同时也碰到一些细节问题,如记住我功能,都是要注意过滤器配置;页面用标签显示shiro属性信息也是要留意过滤器配置,不然是无法生效的,如上流程碰到问题,欢迎大家与我沟通。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值