SpringBoot(3)整合shiro - - 认证

8 篇文章 0 订阅

工程代码建立在SpringBoot(2)的基础上。
默认页面设置
先为网站设置个默认页面,这里设置为登录页面。

方案1:controller里添加一个”/”的映射路径

@RequestMapping("/")
public String index(Model model, HttpServletResponse response) {
    //model.addAttribute("name", "simonsfan");
    return "/login.html";
}

方案2:设置默认的View跳转页面

@Configuration
public class DefaultView extends WebMvcConfigurerAdapter {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("login.html");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
        super.addViewControllers(registry);
    }
}

如上两种方式均可实现在springboot中设置默认页面跳转

设置热部署模式
此处设置比较简单,查一下就知道了

一、后端
这里写图片描述

1、bean

2、dao

3、shiro
configure+Realm

二、前端
这里写图片描述

三、运行
(1)身份验证
1、浏览器中输入访问index页面

This application has no explicit mapping for /error, so you are seeing this as a fallback.

这里写图片描述

于是修改了配置文件,增加了spring.view的配置,浏览器成功定向至login页面


2、login.html页面中引用static下面的jquery-3.3.1.js一直报错,最后没办法就先把js复制到templates下面了,此时猜想可能是被shiro拦截了【后续参数传递时解决,通过指定static静态资源匹配解决】。

修改后成功调用后端checkLogin()。此时注意到此次参照的案例和之前使用shiro的模式不一样,以前是在后台显式调用shiro的login()方法,从而调用起自定义Realm验证方法。此次是在调用这个方法的过程中,被shiro拦截,然后做login验证。但是过程中并未看到自定义Realm的调用。


3、参照的例子中使用form表单提交页面数据,action路径可省略,或者填写”/login”,可以自动调用到shiro的login()验证,走进自定义realm验证逻辑中。换成其他的路径竟然不能实现。。。【后来使用手动调用login实现,该问题和下面卡住的问题是一个】。

替换方案是前端调用到后端的方法后,取得Subject实例,然后手动调用login验证方法,这个是完全可以实现的。


4、目前姑且认为调用没问题,往下走
调用到自定义Realm认证方法时,Dao层service调用时报空指针异常。记得之前刚开始用spring整合shiro的时候就报错过。查看下记录,异常原因是一致的。给ServiceImpl增加@Service注解,Service中使用的Dao层mapper增加@Resource注解,重新调用。(此时Dao层mapper增加注解后,报bean不存在的红线)【后来在mapper中增加@Component注解就好了】


5、重新登录,可以测试出账号不存在,密码不正确的异常。请求到达后台之后,直接调用自定义Realm的doGetAuthenticationInfo()验证身份,通过Dao层接口调用,验证用户名及密码。
密码验证问题:
用户信息是实现存进库中的,此时使用测试用户名,进行手动盐值加密,将值更新进数据库中。再次登录,页面跳转至index界面。


6、问题来了 ,index界面并未显示出来,不过shiro的成功登录设置生效了,且必须先登录(403页面竟然也需要先登录,明明设置了无需权限的)

查找解决办法时,注意到登录成功的页面设置问题,说是在shiro配置中设置的路径会被更改,需重新设置。方法为:先是继承FormAuthenticationFilter,实现onLoginSuccess(),并添加到shiroConfig配置中。但是执行后效果和先前一样,都是跳转了但是没有显示页面。猜想应该就是页面访问的问题。

此时还伴随着一个问题,前端点击登录后,不再进入自定义Realm验证方法。网上看到了好多博客但是都没有解决问题。


7、卡了很久也没找到办法,那就换一种实现吧。使用Subject手动调用login()实现。
实现:
—> login界面不变,使用form,postt提交表单
—> 后端login()中,获取Subject,调用login(),走进自定义Realm身份验证中
—>从库中取得用户信息,生成用户认证Info
—>Info不为空,连同token进入CredentialsMatcher中,调用自定义doCredentialsMatch()
—>验证成功,返回index
—>前端显示index界面

到这里,觉得还是手动触发验证比较好,看得还清楚。



(2)权限认证

1、页面间参数传递
此时使用到jquery,之前出现的js引用问题在这里继续继续跟踪。参考链接
属性配置以及增加配置类都可以解决该问题。

参数传递这里想的是使用前端的cookie或者是使用Session会话中的属性。

session实现:
<1>login.html中按钮点击事件中将用户名置入sessionStorage中

sessionStorage.setItem("username",username)

<2>index.html中从sessionStorage中获取用户名

var username = sessionStorage.getItem("username")

cookie实现

用户经shiro认证,成功登录系统,进入index界面。index界面中添加了增删改查四个按钮,按钮权限由后台经过权限认证实现。


2、权限认证

查询所有人员列表,定位user角色可用,其余按钮均由admin角色可用。

查询
点击查询按钮后,首先调用权限检查方法,进入Realm权限认证方法中。调用service查询用户具备的角色,报错信息如下:

There is no getter for property named 'user' in 'class com.example.bean.SysUser'

此报错其实是因为我在Dao层直接编写了个根据整个User对象查询具备的Role列表,下面还有一处根据整个Role对象查询具备的权限列表。没更好的办法,我将两处各自修改为对应的主键查询。

在库中增加对应的角色信息,在Controller的校验方法中调用hasRole方法后,得到用户的角色、权限信息。

此时验证正确的响应没有返回到前端页面。排查原因,是因为返回的信息和ajax的dataType不一致,导致响应无法解析。

进入success分支,跳转至人员列表查询界面,报错,没找到页面

 No mapping found for HTTP request with URI [/userList.html] in DispatcherServlet with name 'dispatcherServlet'

在Controller中增加了一个对应的mapping方法,然后手动返回userList.html,竟然成功了。

输入用户名,点击查询按钮,调用后端用户列表接口,前端反显结果列表。但是此时的查询Sql较为简单,想着什么办法可以拼接自定义条件进去。查了资料,比较简单的实现方式如下

 @Select("<script>" +
            "select \n" +
            "id,username," +
            "case when locked='0' then '正常'\n" +
            "when locked='1' then '锁定' \n" +
            "end as locked \n" +
            "from sys_users " +
            "where 1=1 " +
            "<if test=\" #{param.username} != null \"> and username like concat(#{param.username},'%')</if>" +
            "</script>")
    List<SysUser> getUserList(@Param("param") Map<String,Object> param);

select语句前后加script,方法中参数前加注解,如果是传入多个参数,各自加注解即可。

此时前端页面多次查询成功页面不刷新,这里就简单调用了一下html(“”)

增加
删除
修改


上述过程是在代码中写死的关于角色,权限的限制,看到网上有直接在方法上添加所需权限、角色的注解实现这个过程的。于是操作了一把,发现注解不生效。查找解决办法,说是shiro-AOP没起作用。

shiroconfiguration中增加

@Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
            = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
在controller中的方法前加上注解
@RequiresPermissions("userInfo:test")
若还没生效,应该是aop没起作用,

解决方法一

shiroconfiguration中增加
@Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }
解决方法二

pom.xml中加入
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
同时application.properties中补充
spring.aop.proxy-target-class=true

两种方法分别试了一下,都可以解决问题。成功进入权限认证方法中,无对应角色或权限则抛出异常。

Request processing failed; nested exception is org.apache.shiro.authz.UnauthorizedException: Subject does not have role [test]] with root cause

对于该异常的处理,需要做拦截,让其无权限的情况下进入403页面。

 @Bean(name="simpleMappingExceptionResolver")
    public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
        Properties mappings = new Properties();
        mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
        mappings.setProperty("UnauthorizedException","403");
        r.setExceptionMappings(mappings);  // None by default
        r.setDefaultErrorView("error");    // No default
        r.setExceptionAttribute("ex");     // Default is "exception"
        return r;
    }

加上此配置之后,异常不再抛出,但是页面仍然没有跳转。此问题和先前设置的无权限403页面应该属于一个问题。觉得前端ajax的调用可以修改下。这个问题下次来更新。


解决:


这篇写了好几天,问题不断,很是折腾。后续来解决问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值