1.首先集成maven依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2.自定义过滤器,获取token信息进行登陆
public class MyFilter extends BasicHttpAuthenticationFilter {
//跨域处理
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
// httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
httpServletResponse.setHeader("Access-control-Allow-Origin", "*");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
response.setCharacterEncoding("utf-8");
return super.preHandle(request, response);
}
//这里看到暂时没有用到,之前看别人demo有用.
/*
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if (isLoginSubmission(request, response)) {
executeLogin(request, response);
} else {
HttpServletResponse response1 = (HttpServletResponse) response;
try {
response1.getWriter().write("no token");
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
return true;
}*/
//拒绝访问后回调到这里
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginAttempt(request, response)) {
try{
executeLogin(request, response);
}catch (Exception e){
HttpServletResponse response1 = (HttpServletResponse) response;
try {
ObjectMapper ob = new ObjectMapper();
Map<String,Object> map = new HashMap<>();
map.put("msg", e.getMessage());
map.put("code","201" );
String s = ob.writeValueAsString(map);
response1.getWriter().write(s);
} catch (IOException ee) {
ee.printStackTrace();
}
return false;
}
} else {
HttpServletResponse response1 = (HttpServletResponse) response;
try {
response1.getWriter().write("no token");
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
return super.onAccessDenied(request, response);
}
//是否具备登陆条件
@Override
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
HttpServletRequest req = (HttpServletRequest) request;
String authorization = req.getHeader("token");
return authorization != null;
}
//进行登陆验证,如果失败getSubject将产生异常,抛到onAccessDenied进行捕获
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader("token");
MyToken token = new MyToken(authorization);
getSubject(request, response).login(token);
return true;
}
//登陆回调,这里没有调用subject.Login,所以用不到
/*@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
System.out.println("ddawdwadaawd");
return super.onLoginFailure(token, e, request, response);
}
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
System.out.println("wadwa21313131111111111");
return super.onLoginSuccess(token, subject, request, response);
}*/
}
3.自定义token
public class MyToken implements AuthenticationToken {
private String token;
public MyToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}
4.自定义的realm
@Component
public class MyRealm extends AuthorizingRealm {
//是否支持验证
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof MyToken;
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String token = (String) principalCollection.getPrimaryPrincipal();
Set role = new HashSet();
if (token.equals("123")) {
role.add("admin");
} else {
role.add("guest");
}
Set perms = new HashSet();
if (token.equals("123")) {
perms.add("ddd");
} else {
perms.add("delete");
}
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(role);
simpleAuthorizationInfo.addStringPermissions(perms);
return simpleAuthorizationInfo;
}
//验证身份
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String token = (String) authenticationToken.getPrincipal();
if (token == null) {
throw new AuthenticationException("没有jwt的token");
}
if (!token.equals("123") && !token.equals("111")) {
throw new UnknownAccountException("验证失败");
}
return new SimpleAuthenticationInfo(token, token, "myRealm");
}
}
5.shiro权限控制中心
@Configuration
public class MyShiroFilter {
@Bean("shiroFilter")
public ShiroFilterFactoryBean bean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
Map<String, Filter> filters = bean.getFilters();
filters.put("jwt", new MyFilter());
filters.put("myRole", new RoleConfig());
filters.put("myPerm", new PermConfig());
Map<String, String> filterRuleMap = new HashMap<>();
filterRuleMap.put("/login", "anon");
filterRuleMap.put("/index", "jwt,myRole[admin]");
filterRuleMap.put("/test", "jwt");
filterRuleMap.put("/**", "jwt");
bean.setFilterChainDefinitionMap(filterRuleMap);
bean.setUnauthorizedUrl("/fail");
return bean;
}
//安全管理器
@Bean
public DefaultWebSecurityManager manager(MyRealm realm) {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(realm);
//这里设置不创建session
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator evaluator = new DefaultSessionStorageEvaluator();
evaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(evaluator);
manager.setSubjectDAO(subjectDAO);
return manager;
}
/**
* 下面的代码是添加注解支持
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
// 强制使用cglib,防止重复代理和可能引起代理出错的问题
// https://zhuanlan.zhihu.com/p/29161098
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
6.自定义的roles,perms过滤
public class PermConfig extends PermissionsAuthorizationFilter {
@Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
Subject subject = this.getSubject(request, response);
String[] rolesArray = (String[]) mappedValue;
if (rolesArray == null || rolesArray.length == 0) {
//no roles specified, so nothing to check - allow access.
return true;
}
for (int i = 0; i < rolesArray.length; i++) {
if (subject.isPermitted(rolesArray[i])) {
return true;
}
}
return false;
}
}
public class RoleConfig extends AuthorizationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
Subject subject = this.getSubject(servletRequest, servletResponse);
String[] rolesArray = (String[]) o;
if (rolesArray == null || rolesArray.length == 0) {
//no roles specified, so nothing to check - allow access.
return true;
}
for (int i = 0; i < rolesArray.length; i++) {
if (subject.hasRole(rolesArray[i])) {
return true;
}
}
return false;
}
}
7.controller
@RestController
public class IndexController {
@GetMapping("login")
public Object login(@RequestParam(required = true) String name, @RequestParam(required = true) String pass) {
if (name.equals("gao") && pass.equals("123")) {
return "123";
} else {
throw new ExceptionA(2222,"登陆失败");
}
}
@GetMapping("index")
public Object index() {
return "测试role";
}
@GetMapping("fail")
public Object fail() {
Map map = new HashMap<>();
map.put("message", "授权失败");
return map;
}
@RequiresPermissions(value = "delete")
@GetMapping("test")
public Object test() {
return "测试资源";
}
}
该demo过于简陋,并没有涉及到jwt,都将登陆信息写死了...但是思路是对的,在login接口中生成jwt的token,返给前端,然后后台带着token访问接口,拦截器拿到token,然后进行验证处理;