【Jeecg学习】Jeecg(shiro+Jwt)实现多Realm的控制


前言

shiro主张的是将主体的认证和权限管理交由用户自己定义,所以只需要自定以完realm后注入到securityManager就行

一、ShiroConfig 修改

修改securityManager方法
添加modularRealmAuthenticator方法

public class ShiroConfig {

    /**
     *
     *  SecurityManager 是 Shiro 架构的核心,通过它来链接Realm和用户(文档中称之为Subject.)
     *
     * @param appRealm
     * @param desktopRealm
     * @param userModularRealmAuthenticator 自定义 RealAuthenticator
     * @return
     */
    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager(@Qualifier("appRealm") AppRealm appRealm,
                                                     @Qualifier("desktopRealm") DesktopRealm desktopRealm,
                                                     @Qualifier("userModularRealmAuthenticator") UserModularRealmAuthenticator userModularRealmAuthenticator) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//        securityManager.setRealm(myRealm);
        securityManager.setAuthenticator(userModularRealmAuthenticator);
        List<Realm> realms = new ArrayList<>();
        //添加多个Realm
        realms.add(desktopRealm);
        realms.add(appRealm);
        securityManager.setRealms(realms);


        /*
         * 关闭shiro自带的session,详情见文档
         * http://shiro.apache.org/session-management.html#SessionManagement-
         * StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        //自定义缓存实现,使用redis
        securityManager.setCacheManager(redisCacheManager());
        return securityManager;
    }

    /**
     * 系统自带的Realm管理,主要针对多realm
     * */
    @Bean
    public ModularRealmAuthenticator modularRealmAuthenticator(){
        //自己重写的ModularRealmAuthenticator
        UserModularRealmAuthenticator modularRealmAuthenticator = new UserModularRealmAuthenticator();
        modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());//这里为默认策略:如果有一个或多个Realm验证成功,所有的尝试都被认为是成功的,如果没有一个验证成功,则该次尝试失败
        return modularRealmAuthenticator;
    }
}

二、复制ShiroRealm类

针对业务复制ShiroRealm类

并添加getName() 方法

@Component
@Slf4j
public class DesktopRealm extends AuthorizingRealm {
	...
	@Override
	public String getName() {
		return "Desktop";
	}
	...
	
@Component
@Slf4j
public class AppRealm extends AuthorizingRealm {
	...
	@Override
	public String getName() {
		return "App";
	}
	...
	

三、JwtFilter和JwtToken修改

@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {
	...
	
	@Override
	protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		String token = httpServletRequest.getHeader(DefContants.X_ACCESS_TOKEN);
		String loginType = httpServletRequest.getHeader(DefContants.X_LOGIN_TYPE);

		JwtToken jwtToken = new JwtToken(token, loginType);
		// 提交给realm进行登入,如果错误他会抛出异常并被捕获
		getSubject(request, response).login(jwtToken);
		// 如果没有抛出异常则代表登入成功,返回true
		return true;
	}
	
	...
}
	
public class JwtToken implements AuthenticationToken {

    private static final long serialVersionUID = 1L;
    private String token;
    // 增加
    private String loginType;

    public JwtToken(String token) {
        this.token = token;
    }

	// 增加
    public JwtToken(String token, String loginType) {
        this.token = token;
        this.loginType = loginType;
    }

    @Override
    public Object getPrincipal() {
        return token;
    }

    @Override
    public Object getCredentials() {
        return token;
    }

    public void setLoginType(String loginType) {
        this.loginType = loginType;
    }

    public String getLoginType() {
        return loginType;
    }
}

四、增加UserModularRealmAuthenticator类

/**
 *
 *  当配置了多个Realm时,我们通常使用的认证器是shiro自带的
 *  org.apache.shiro.authc.pam.ModularRealmAuthenticator,
 *  其中决定使用的Realm的是doAuthenticate()方法
 */
@Slf4j
@Component
public class UserModularRealmAuthenticator extends ModularRealmAuthenticator {

    @Override
    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("UserModularRealmAuthenticator:method doAuthenticate() 执行 ");
        // 判断getRealms()是否返回为空
        assertRealmsConfigured();

        // 所有Realm
        Collection<Realm> realms = getRealms();

        JwtToken jwtToken = (JwtToken) authenticationToken;
        String loginType = jwtToken.getLoginType();
        // 增加默认
        if(StrUtil.isEmpty(loginType)){
            loginType = "App";
        }
        Realm realm = null;
       for (Realm realmItem : realms) {
           log.info("Realm>>>>{}", realmItem.getName());
           log.info("Realm>>>>{}", loginType);
           if (realmItem.getName().contains(loginType)) {
               log.info("Realm>>{}", "Desktop请求");
               realm = realmItem;
               break;
           }
           if (realmItem.getName().contains(loginType)) {
               log.info("Realm>>{}", "App端请求");
               realm = realmItem;
               break;
           }
       }
        if(realm == null){
            return null;
        }
        return doSingleRealmAuthentication(realm, authenticationToken);

    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shiro 支持使用 JSON Web Token (JWT) 实现单点登录 (SSO)。 实现步骤如下: 1. 在服务端生成 JWT 并返回给客户端。 2. 客户端保存 JWT 并在请求中加上 HTTP Header,如 "Authorization: Bearer JWT"。 3. 服务端收到请求后验证 JWT 的有效性。 4. 如果 JWT 有效,则允许访问请求的资源。 以下是一个使用 Shiro 实现 JWT 验证的示例代码: ```java import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; public class JwtRealm extends AuthorizingRealm { private String secretKey; public JwtRealm(String secretKey) { this.secretKey = secretKey; } @Override public boolean supports(AuthenticationToken token) { return token instanceof JwtToken; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 这里可以根据 JWT 中的自定义字段来进行权限控制 return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { JwtToken jwtToken = (JwtToken) token; String jwt = jwtToken.getPrincipal().toString(); Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody(); // 验证 JWT 是否过期 if (claims.getExpiration().before(new Date())) { throw new AuthenticationException("JWT 已过期"); } // 这里可以使用 claims 中的用户信息来创建 SimpleAuthenticationInfo 对象 return new SimpleAuthenticationInfo(jwt, jwt, "j

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值