Spring Boot 结合shiro做第三方登录验证

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/he1lo/article/details/52244283

Spring Boot 结合shiro做第三方登录验证

1、首先,说一下我的具体实现思路。在做spring boot拦截器的过程中,开始我准备用spring security来实现,但是研究了一段时间之后发现spring security的集成度太高,需要修改的东西比较多,而且对它本身的使用方法不是很了解,后来转而使用Apache shiro。由于是第三方登录,是不需要我来验证密码的。最开始,我陷入了一个误区,将获取到的用户密码提交到Realm的实现类里面去,然后和用户名封装在一起进行第三方api访问。然而,在我处理http的post方法时,是用LoginController处理的,这里面调用Realm实现类的doGetAuthenticationInfo()方法,主要是用token将username和password封装起来。而在对password进行封装时,shiro使用了一个加密方法,好像是不可逆的。所以,当执行到doGetAuthenticationInfo方法时,我写在里面的api访问方法就不能取到正确的密码了。所以,我的解决方法时在把api访问登录写在LoginController里面,最后解析登录的返回值。判断返回值,如果是登陆成功,则调用Realm方法,否则不调用。这样就把api访问和shiro验证彻底分开写了,降低了这两个模块的耦合度。
2、Spring Boot使用的是javaConfig的方式进行配置,而很多关于spring boot使用shiro的文章都是用xml配置的,然而也有一些博客可供参考,如spring boot 集成shiro的配置这篇博客提到的方法。其中ShiroRealmImpl是realm的实现类。因为Realm类时继承了AuthenticatingRealm类,所以在写具体的ShiroRealmImpl类时,可以继承AuthenticatingRealm类,也可以通过实现Realm接口的具体方法。以下会具体提到这个类中的方法。
3、最后shiroFilter的配置很重要,其中有几点需要注意

@Bean(name = "shiroFilter")  
public ShiroFilterFactoryBean getShiroFilterFactoryBean() {  
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();  
    shiroFilterFactoryBean  
            .setSecurityManager(getDefaultWebSecurityManager());  
    shiroFilterFactoryBean.setLoginUrl("/app/pages/login.html");  
    shiroFilterFactoryBean.setSuccessUrl("/app/views/dashboard.html");  
    filterChainDefinitionMap.put("/app/views/**", "authc");  
    filterChainDefinitionMap.put("/app/pages/**", "anon");  
    shiroFilterFactoryBean  
            .setFilterChainDefinitionMap(filterChainDefinitionMap);  
    return shiroFilterFactoryBean;  
}

其中LoginUrl是用户首次进入时的登陆页面,SuccessUrl是登陆成功后自动跳转的页面,authc是需要用户登陆才能访问的页面,anon是不需要登陆就能直接访问的页面。我在这里配置成了目录的形式。
4、shiro的Realm实现类继承了AuthenticatingRealm类,这个类里有两个主要方法,doGetAuthenticationInfo和doGetAuthorizationInfo,其中前者是用作登录认证的,后者是用作权限管理的。我暂时不考虑权限,所以只重写了doGetAuthenticationInfo方法。这个方法如果返回一个SimpleAccount 对象则认证通过,如果返回值为空或者异常,则认证不通过。所以我这里是只要执行了这个方法,就认证通过,故只返回该对象。(有的写法是认证不通过返回空值)

public class ShiroRealmImpl extends AuthenticatingRealm {

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

    UsernamePasswordToken token1 = (UsernamePasswordToken) token;
    String username = token1.getUsername();
    SimpleAccount info = new SimpleAccount(username, token1.getPassword(),this.getName());
    return info;
    }
}

LoginController里面如果api登录通过后则执行下面的代码,我是通过result判断的。

if(result==0){
            //获取SecurityManager工厂
            Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory();
            //得到SecurityManager实例并绑定给SecurityUtils  
            org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();  
            SecurityUtils.setSecurityManager(securityManager);  
            //得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证) 
            Subject subject = SecurityUtils.getSubject();
            String pwd = result.toString();
            UsernamePasswordToken token = new UsernamePasswordToken(username,pwd);
            try{
                //登录,即身份验证  
                subject.login(token);
            }catch (AuthenticationException e){
                token.clear();
            }
        }

总结如下:首先配置shiro,并配置第三方登陆需要的具体参数,然后用http提交用户名和密码,并在LoginController里面设置第三方登录需要的请求参数和签名,最后用HTTPClient进行api访问,将得到的json数据解析后进行判断,如果登陆成功,则执行subject.login(token)方法,该方法会调用Realm实现类中的doGetAuthenticationInfo方法,进行登陆认证。只要认证函数返回对象SimpleAccount的参数没有错误,一般都可以成功。如果捕获到这种错误:org.apache.shiro.authc.UnknownAccountException:Realm [com.cn21。account.crm.module.ShiroRealmImpl@86d0d48] was unable to find account data for the submitted AuthenticationToken [org.apache.shiro.authc.UsernamePasswordToken 则有可能是LoginController里面封装的token不对或者对象SimpleAccount里面的参数不对。

展开阅读全文

没有更多推荐了,返回首页