application配置
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/companydb
username: root
password: 123456
redis:
database: 2
host: localhost
port: 6379
mybatis:
mapper-locations: classpath*:mapper*Mapper.xml
xy:
jwt:
secret: xy@123 # 登录校验的密钥
expire: 180 # 过期时间,单位分钟
添加依赖
4.0.0 org.springframework.boot spring-boot-starter-parent2.6.2 com.itluma login01160.0.1-SNAPSHOT login0116 Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-testtest mysql mysql-connector-java5.1.36 com.alibaba druid1.2.8 org.mybatis.spring.boot mybatis-spring-boot-starter1.3.2 org.springframework spring-jdbc5.3.6 org.apache.shiro shiro-spring1.4.1 org.projectlombok lombok1.18.20 provided com.alibaba fastjson1.2.28 io.jsonwebtoken jjwt0.9.0 joda-time joda-time2.10.4 org.apache.commons commons-lang3org.springframework.boot spring-boot-starter-data-redisorg.springframework.boot spring-boot-maven-plugin
实体类user
package com.itluma.login.entity;
import lombok.Data;
@Data
public class User {
private Integer id;
private String username;
private String password;
}
shiro核心配置类
package com.itluma.login.config;
import com.itluma.login.filter.XyFormAuthenticationFilter;
import com.itluma.login.realm.XyRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.util.linkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Autowired
private XyRealm realm;
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(realm);
return defaultWebSecurityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
Map map = new linkedHashMap<>();
//将自定义的过滤器添加到filterFactoryBean中
Map filterMap = new linkedHashMap<>();
filterMap.put("jwt",new XyFormAuthenticationFilter());
filterFactoryBean.setFilters(filterMap);
filterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//无需认证就可访问
map.put("/user/login","anon");
map.put("/user/captchaImage","anon");
map.put("/","anon");
map.put("*.html","anon");
map.put("*.css","anon");
map.put("*.js","anon");
map.put("/profile
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
ObjectMapper objectMapper = new ObjectMapper();
//其实就是一个Jackson的转换器
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
objectMapper.activateDefaultTyping(LaissezFaireSubTypevalidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
redisTemplate.setKeySerializer(RedisSerializer.string());
// hash的key也采用String的序列化方式
redisTemplate.setHashKeySerializer(RedisSerializer.string());
// value序列化方式采用jackson
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
controller
package com.itluma.login.controller;
import com.itluma.login.service.UserService;
import com.itluma.login.utils.JwtProperties;
import com.itluma.login.utils.RedisUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.cookie;
import javax.servlet.http.HttpServletResponse;
@RestController
@EnableConfigurationProperties(JwtProperties.class)
@RequestMapping("/user")
public class LoginController {
@Autowired
private JwtProperties jwtProperties;
@Autowired
private UserService userService;
@Autowired
private RedisUtil redisUtil;
@RequestMapping("/login")
public String toLogin(String username,String password){
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.getSubject();
try{
subject.login(token);
//生成token
String reToken = userService.generateToken(jwtProperties.getSecret(), jwtProperties.getExpire());
redisUtil.set("token",reToken,3600);
return "ok";
}catch (Exception e){
return "notok";
}
}
@RequestMapping("/getInfo")
public String getInfo(){
return "yes";
}
@RequestMapping("/getInfo2")
public String getInfo2(){
return "yes2";
}
}
mapper接口
package com.itluma.login.mapper;
import com.itluma.login.entity.User;
public interface UserMapper {
User searchUserByUsername(String username);
}
service层接口
package com.itluma.login.service;
import com.itluma.login.entity.User;
public interface UserService {
public User selectUser(String username);
public String generateToken(String secret, Integer expireTime);
}
对应实现类
package com.itluma.login.service.impl;
import com.itluma.login.entity.User;
import com.itluma.login.mapper.UserMapper;
import com.itluma.login.service.UserService;
import com.itluma.login.utils.JwtUtils;
import com.itluma.login.vo.UserInfo;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserServiceImpl implements UserService{
@Resource
private UserMapper userMapper;
@Override
public User selectUser(String username) {
User user = userMapper.searchUserByUsername(username);
return user;
}
@Override
public String generateToken(String secret, Integer expireTime) {
User user = (User) SecurityUtils.getSubject().getPrincipal();
UserInfo userInfo = new UserInfo();
userInfo.setId(user.getId().longValue());
userInfo.setUsername(user.getUsername());
try {
String token = JwtUtils.generateToken(userInfo, secret, expireTime);
return token;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
自定义realm
package com.itluma.login.realm;
import com.itluma.login.entity.User;
import com.itluma.login.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class XyRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
User user = userService.selectUser(username);
if(user != null){
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(),"XyRealm");
return authenticationInfo;
}
return null;
}
}
自定义过滤器filter
package com.itluma.login.filter;
import com.alibaba.fastjson.JSONObject;
import com.itluma.login.utils.JwtProperties;
import com.itluma.login.utils.RedisUtil;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
@Configuration
@EnableConfigurationProperties(JwtProperties.class)
public class XyFormAuthenticationFilter extends FormAuthenticationFilter {
@Autowired
private RedisUtil redisUtil;
@Autowired
private JwtProperties jwtProperties;
private static final Logger log = LoggerFactory.getLogger(FormAuthenticationFilter.class);
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
System.out.println("过滤器执行啦");
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
if (log.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
}
return executeLogin(request, response);
} else {
if (log.isTraceEnabled()) {
log.trace("Login page view.");
}
//allow them to see the login page ;)
return true;
}
} else {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse) response;
if(req.getMethod().equals(RequestMethod.OPTIONS.name())) {
resp.setStatus(HttpStatus.OK.value());
return true;
}
if (log.isTraceEnabled()) {
log.trace("Attempting to access a path which requires authentication. Forwarding to the " +
"Authentication url [" + getLoginUrl() + "]");
}
//对token进行判断
//前端Ajax请求时requestHeader里面带一些参数,用于判断是否是前端的请求
resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setContentType("application/json; charset=utf-8");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
JSonObject result = new JSonObject();
result.put("message", "请登录!");
result.put("statusCode", 401);
out.println(result);
out.flush();
out.close();
}
return false;
}
}
.xml文件
到此,完结,散花~



