NutzCN Logo
问答 nutzbook中和shiro集成的问题
发布于 2758天前 作者 qq_64f81159 1650 次浏览 复制 上一个帖子 下一个帖子
标签:

我看nutzbook中貌似没有这个登陆的方法了

@At
    @Filters // 覆盖UserModule类的@Filter设置,因为登陆可不能要求是个已经登陆的Session
    @POST
    public Object login(@Param("username")String username, 
            @Param("password")String password, 
            @Param("captcha")String captcha,
            @Attr(scope=Scope.SESSION, value="nutz_captcha")String _captcha,
            HttpSession session) {
        NutMap re = new NutMap();
        if (!Toolkit.checkCaptcha(_captcha, captcha)) {
            return re.setv("ok", false).setv("msg", "验证码错误");
        }
        int userId = userService.fetch(username, password);
        if (userId < 0) {
            return re.setv("ok", false).setv("msg", "用户名或密码错误");
        } else {
            session.setAttribute("me", userId);
            // 完成nutdao_realm后启用.
            // SecurityUtils.getSubject().login(new SimpleShiroToken(userId));
            return re.setv("ok", true);
        }
    }

只有这个方法

	@GET
	@At("/login")
	@Ok("jsp:jsp.user.login")
	public void loginPage() {}

这个不是跳转到login.jsp页面的方法吗,我看这个登录页面中

  $("#login_button").click(function () {
                // 提交数据
                $.ajax({
                    url: base + "/user/login",
                    type: "POST",
                    data: $('#loginForm').serialize(),
                    error: function (request) {
                        alert("Connection error");
                    },
                    dataType: "json",
                    success: function (data) {
                        if (data && data.ok) {
                            //alert("登陆成功");
                            window.location = base + "/home";
                        } else {
                            var emsg = data.msg;
                            if (emsg.substr(0, 3) == '验证码') {
                                var $captf = $('.with-captcha .md-text-field');
                                $captf.find('.err-tip').html(emsg);
                                $captf.addClass('has-err');
                                $captf.find('input').focus();
                                $captf.one('focusout', function () {
                                    $captf.removeClass('has-err');
                                });
                            } else {
                                alert(emsg);
                            }
                        }
                    }
                });
            });

这个url不是有到了上面那个登陆页面的中转方法了吗,但是我测试的时候确实可以跳转到自定义的realm方法中

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		CaptchaUsernamePasswordToken upToken = (CaptchaUsernamePasswordToken) token;
		
		if (Strings.isBlank(upToken.getCaptcha()))
			throw new AuthenticationException("验证码不能为空");
		String _captcha = Strings.sBlank(SecurityUtils.getSubject().getSession(true).getAttribute(Toolkit.captcha_attr));
		if (!upToken.getCaptcha().equalsIgnoreCase(_captcha))
			throw new AuthenticationException("验证码错误");
		
		User user = dao().fetch(User.class, Cnd.where("name", "=", upToken.getUsername()));
        if (user == null)
            return null;
        if (user.isLocked()) 
            throw new LockedAccountException("Account [" + upToken.getUsername() + "] is locked.");
        SimpleAccount account = new SimpleAccount(user.getId(), user.getPassword(), getName());
        account.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
        return account;
	}

为什么第一次在地址栏输入user/login的时候是跳转到登陆页面,没有经过这个realm方法,点击登陆的时候这个地址却可以跳转到对应的realmz中啊 ,我自己试验的时候却出现了connection error的错误
配置如下
web.xml中

10 回复

接上面 不小心发出去了


<listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> </listener> <filter> <filter-name>ShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> </filter> <filter-mapping> <filter-name>ShiroFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping> <filter> <filter-name>DruidWebStatFilter</filter-name> <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class> <init-param> <param-name>exclusions</param-name> <param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,/rs/*</param-value> </init-param> </filter> <filter-mapping> <filter-name>DruidWebStatFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- <filter> <filter-name>nutz</filter-name> <filter-class>net.wendal.nutzbook.mvc.NutzBookNutFilter</filter-class> <init-param> <param-name>modules</param-name> <param-value>com.kanq.main.MainModule</param-value> </init-param> </filter> <filter-mapping> <filter-name>nutz</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping> --> <filter> <filter-name>nutz</filter-name> <filter-class>org.nutz.mvc.NutFilter</filter-class> <init-param> <param-name>modules</param-name> <param-value>com.kanq.MainModule</param-value> </init-param> </filter> <filter-mapping> <filter-name>nutz</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>DruidStatView</servlet-name> <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DruidStatView</servlet-name> <url-pattern>/druid/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index</welcome-file> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <error-page> <error-code>500</error-code> <location>/WEB-INF/jsp/500.jsp</location> </error-page>

shiro.ini中

[main]
nutzdao_realm = com.kanq.shiro.realm.SimpleAuthorizingRealm

authc = org.nutz.integration.shiro.SimpleAuthenticationFilter
authc.loginUrl  = /user/login
logout.redirectUrl= /user/login

[urls]
/rs/*        = anon
/user/logout = logout
/user/error  = anon
/user/login  = anon
/user/profile/active/mail = anon

自定义realm方法

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.nutz.dao.Dao;
import org.nutz.mvc.Mvcs;
import org.nutz.integration.shiro.SimpleShiroToken;
import com.kanq.bean.Permission;
import com.kanq.bean.Role;
import com.kanq.bean.User;

public class SimpleAuthorizingRealm extends AuthorizingRealm {
	// ShiroFilter先于NutFilter初始化化,所以无法使用注入功能
	protected Dao dao; 

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		 if (principals == null) {
	            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
	        }
	        int userId = (Integer) principals.getPrimaryPrincipal();
	        User user = dao().fetch(User.class, userId);
	        if (user == null)
	            return null;
	        if (user.isLocked())
	            throw new LockedAccountException("Account [" + user.getName() + "] is locked.");

	        SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();
	        user = dao().fetchLinks(user, null);
	        if (user.getRoles() != null) {
	            dao().fetchLinks(user.getRoles(), null);
	            for (Role role : user.getRoles()) {
	                auth.addRole(role.getName());
	                if (role.getPermissions() != null) {
	                    for (Permission p : role.getPermissions()) {
	                        auth.addStringPermission(p.getName());
	                    }
	                }
	            }
	        }
	        if (user.getPermissions() != null) { // 特许/临时分配的权限
	            for (Permission p : user.getPermissions()) {
	                auth.addStringPermission(p.getName());
	            }
	        }
	        return auth;
	}

	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        SimpleShiroToken upToken = (SimpleShiroToken) token;
        // upToken.getPrincipal() 的返回值就是SimpleShiroToken构造方法传入的值
        // 可以是int也可以是User类实例,或任何你希望的值,自行处理一下就好了
        User user = dao().fetch(User.class, ((Integer)upToken.getPrincipal()).longValue());
        if (user == null)
            return null;
        if (user.isLocked())
            throw new LockedAccountException("Account [" + user.getName() + "] is locked.");
        return new SimpleAccount(user.getId(), user.getPassword(), getName());
    }

    /**
     * 覆盖父类的验证,直接pass. 在shiro内做验证的话, 出错了都不知道哪里错
     */
    protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
    }

    public SimpleAuthorizingRealm() {
        this(null, null);
    }

    public SimpleAuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager, matcher);
        setAuthenticationTokenClass(SimpleShiroToken.class); // 非常非常重要,与SecurityUtils.getSubject().login是对应关系!!!
    }

    public SimpleAuthorizingRealm(CacheManager cacheManager) {
        this(cacheManager, null);
    }

    public SimpleAuthorizingRealm(CredentialsMatcher matcher) {
        this(null, matcher);
    }

    public Dao dao() {
        if (dao == null) {
            dao = Mvcs.ctx().getDefaultIoc().get(Dao.class, "dao");
            return dao;
        }
        return dao;
    }

    public void setDao(Dao dao) {
        this.dao = dao;
    }

}

chain.js

var chain={
"default" : {
"ps" : [
"com.kanq.mvc.LogTimeProcessor",
"org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor",
"org.nutz.mvc.impl.processor.EncodingProcessor",
"org.nutz.mvc.impl.processor.ModuleProcessor",
"org.nutz.integration.shiro.NutShiroProcessor",
"org.nutz.mvc.impl.processor.ActionFiltersProcessor",
"org.nutz.mvc.impl.processor.AdaptorProcessor",
"org.nutz.mvc.impl.processor.MethodInvokeProcessor",
"org.nutz.mvc.impl.processor.ViewProcessor"
],
"error" : 'org.nutz.mvc.impl.processor.FailProcessor'
}
};

这个是缺少什么配置吗?

你看的是很老的nutzbook?

1.3的。。我想试着一个个的往上面搭。

暂时不考虑redis ,ehcache这些 就是shiro和nutz集成 不加密也可以 这个需要哪些配置

还是有点不明白为什么没有调用 SecurityUtils.getSubject().login(new SimpleShiroToken(userId));可以直接调用shiro这一步是在哪里完成的。

没进入口方法?不是post过来?

不是这个意思啊 我的意思是

 public SimpleAuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager, matcher);
        setAuthenticationTokenClass(SimpleShiroToken.class); // 非常非常重要,与SecurityUtils.getSubject().login是对应关系!!!
    }

realm定义为SimpleAuthorizingRealm的时候是不是必须主动调用SecurityUtils.getSubject().login(new SimpleShiroToken(userId));
是因为shrio.ini中自定义的过滤器为
authc = org.nutz.integration.shiro.SimpleAuthenticationFilter
而在nutzbook中shiro.ini中自定义的过滤器为
authc = org.nutz.integration.shiro.CaptchaFormAuthenticationFilter
nutzbook中的这个过滤器有一个创建AuthenticationToken authenticationToken = createToken(request, ac.getResponse()); token的方法,而SimpleAuthenticationFilter中却没有创建token的方法
而NutDaoRealm这个代码用的

 public NutDaoRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager, matcher);
        setAuthenticationTokenClass(CaptchaUsernamePasswordToken.class);
    }

简单来说就是shiro.ini中配置的filter不同 导致如果用 org.nutz.integration.shiro.SimpleAuthenticationFilter 这个的话需要主动SecurityUtils.getSubject().login(new SimpleShiroToken(userId))调用这个登陆的方法
org.nutz.integration.shiro.CaptchaFormAuthenticationFilter
这个的话不需要主动调用SecurityUtils.getSubject().login(token)调用这个登陆的方法 。

别用CaptchaFormAuthenticationFilter了

添加回复
请先登陆
回到顶部