shiro使用WebService进行验证的实现

先说说项目中的实际需求。首先项目是有shiro的,也有一套完整的登录认证系统,能够实现使用缓存/dao进行登录用户名密码的校验。然后最近有一个需求,需要实现手机端的登录,登录的请求链接与web端不同,验证是由另外一台服务器进行验证的,使用webservice进行通信。

总结一下,也就是说需要实现一套使用WebService的登录接口。

我使用的解决方案是开放一个无需验证的登录接口给app端使用,在这个接口中调用登录的方法,并且使用webService去进行用户名密码的校验。

1、修改配置文件

在shiro的配置文件中,增加无需验证的登录接口

<bean name="shiroFilterChainDefinitions" class="java.lang.String">
<constructor-arg>
<value>
${adminPath}/app/user/login = anon
${adminPath}/app/user/notAuthorized = user
${adminPath}/app/user/sessionTimeout = anon

</value>
</constructor-arg>
</bean>

2、自定义的Token

/**
 * 自定义的移动端登录token,因为用户名和密码不需要本系统进行校验,所以只需要保存是否校验通过和校验通过后的用户id
 */
public class AppToken extends AuthenticationToken {
    private static final long serialVersionUID = 8587329689973009518L;
    private String checked = null;  //webService的校验是否通过
    private String userId = null;   //登录用户的id
    private boolean isRememberMe = false;   //是否勾选记住我

    public AppToken(String userId, String ticket) {
        this.userId = userId;
        this.checked = ticket;
    }

    /**
     * 获取当前token的身份,即用户id
     * @return
     */
    public Object getPrincipal() {
        return this.userId;
    }

    /**
     * 获取当前用户的凭证,即是否认证通过
     * @return
     */
    public Object getCredentials() {
        return this.checked;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public boolean isRememberMe() {
        return this.isRememberMe;
    }

    public void setRememberMe(boolean isRememberMe) {
        this.isRememberMe = isRememberMe;
    }
}

 

 

3、自定义的Realm,并且加入到配置文件中的配置中去

/**
 * 自定义的移动端认证器,并不进行任何的认证工作,只是为当前用户处理session
 */
@Service
public class AppRealm extends AbstractCustomRealm {
    private SystemService systemService;
    private SystemAuthorizingRealm realm;
    private String name;
    private Logger logger = Logger.getLogger(getClass());


    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public boolean supports(AuthenticationToken authenticationToken) {
        return authenticationToken!=null;
    }

    @Override
    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        if (! (authenticationToken instanceof AppToken)) return null;//只有通过app登录接口进来的请求才能使用该认证器
        AppToken token = (AppToken)authenticationToken;
        Object principal = token.getPrincipal();    //获取token中的身份,是用户的id
        User user = getSystemService().getUser((String) principal);//从系统缓存中获取当前用户的信息
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(new SystemAuthorizingRealm.Principal(user, false),token.getCredentials(),user.getLoginName());//创建Info对象,并不进行校验
        return authenticationInfo;
    }
 
  

  

@Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return getRealm().doGetAuthorizationInfo(principalCollection); } private SystemService getSystemService() { if (systemService == null){ systemService = SpringContextHolder.getBean(SystemService.class); } return systemService; } private SystemAuthorizingRealm getRealm() { if(realm == null){ realm = SpringContextHolder.getBean(SystemAuthorizingRealm.class); } return realm; }

加入配置文件

    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realms">
             <list>
                <ref bean = "appRealm"/>
                <ref bean = "systemAuthorizingRealm"/>
            </list>
        </property>
        <property name="sessionManager" ref="sessionManager" />
        <property name="cacheManager" ref="shiroCacheManager" />
        <property name="authenticator" ref="authenticator"/>
    </bean>

 

4、完成接口,在接口中对用户名和密码进行处理

@Controller
@RequestMapping(value = "${adminPath}/" + AppConst.AppUser_Action)
public class AppUserController extends BaseController {
    @Autowired
    private SystemService systemService;
private String oaWsUrl = "test"

    @ResponseBody
    @RequestMapping(value = "login")
    public String login(UserLoginVo loginVo) {
    Result res = new Result();
try { AppToken phoneToken = null; boolean app = false; User user = null; String result = UserAuthWsClient.authUserOAWS(loginVo.getUsername(), loginVo.getPassword(), oaWsUrl); String[] results = result.split("-"); if (!"0".equals(results[0])){ if (results.length > 1) { logger.error(results[1]); } logger.debug("移动端登录(userid: "+loginVo.getUsername()+")登录失败."); res.setMessage("用户名或者密码错误,请重新输入"); res.setCode(ResponseVo.FAIL); return res; } if ("0".equals(results[0])) { String JC = loginVo.getUsername() ; user = UserUtils.get(JC); if (user != null) { if (user.getDelFlag() == 0) { app = true; } } if(app){ phoneToken = new AppToken(user.getId(), "checked"); } } if(!app){ //本系统中没有该用户,判断登录失败 res.setMessage("登录失败, 请联系管理员"); res.setCode(ResponseVo.FAIL); }else{ Subject subject = SecurityUtils.getSubject(); try { UserUtils.clearCache(); subject.login(phoneToken); logger.debug("移动端登录(userid: "+user.getId()+") 登录成功,"); res.setMessage("登陆成功"); res.setBody(loginVo); res.setCode(ResponseVo.SUCCESS); } catch (AuthenticationException e) { logger.debug("移动端登录(userid: "+user.getId()+")登录失败."); logger.error(e.getMessage(),e); res.setMessage("用户名或者密码错误,请重新输入"); res.setCode(ResponseVo.FAIL); } return res; } }
    }
  }
}

 

总结一下,因为用户名和密码的校验不在本系统内完成,所以对用户名和密码就不需要传入到shiro相关的流程中,直接使用继承自CachingRealm的自定义认证器AbstractCustomRealm ,在这里面不会对token和info的一致性进行校验,因此就不需要关心账号和密码了。

如果是自定的Realm继承自 AuthorizingRealm,那么AuthorizingRealm还会对token和info的一致性进行校验,只有当校验成功后才算是登录成功,否则抛出异常登录失败

转载于:https://www.cnblogs.com/pengjian-one/p/7428055.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值