- 浏览: 562527 次
- 性别:
- 来自: 长沙
文章分类
- 全部博客 (145)
- apache-struts (3)
- apache-shiro (4)
- apache-wicket (1)
- spring (34)
- spring-data-jpa (2)
- spring-mvc (20)
- spring-security (1)
- spring-webflow (1)
- hibernate (2)
- mongodb (1)
- ibatis (5)
- mysql (4)
- 开源组件 (18)
- java (3)
- maven (7)
- jBPM (1)
- EJB (1)
- JMS (2)
- servlet / jsp (9)
- javascript / jquery (10)
- 工作技巧 (12)
- ubuntu (6)
- bootstrap (10)
- javaee (1)
- 他山石 (7)
- jetbrick (1)
最新评论
-
yubao2008:
[size=x-small]为什么我也这样试了, 就是没有生效 ...
javax.servlet.http.HttpServletResponse 得到 status_code -
chenrl:
...
SpringMVC杂记(十五) spring-mvc controller 的切面 -
LONGTENGLONG:
你好,这样配置的,得到的集合为空,是什么原因?
apache-shiro杂记(一) 统计在线用户数目 -
xiafengfeiwu:
[flash=200,200][url]引用[/url][/f ...
apache-shiro 学习笔记 -
3108493554:
你好 ,有些问题想请教下,加下我qq310849354,你这上 ...
SpringMVC杂记(十二) 自定义Interceptor从Active Directory得到域信息
我的SpringSecurity实践
(一) 数据库与实体类设计(mysql)
显然这种设计方式实际上比较常见的,用户与角色是多对多关系;角色与权限也是多对多关系。
下面是实体类(为了节约篇幅getter和setter以及ORM相关的元注释略去)
(二) 编写重要的UserDetailsService实现类
虽然SpringSecurity框架提供的接口很多,真正要亲自实现的不多三个而已
(三) 编写Spring Security 配置文件
尽管SpringSecurity提供了<http>元素来简化配置,简化过后有相当多的细节被隐藏起来了。
有时候想改变一下框架的默认行为十分不便。我还是用传统的Bean方式。
这样虽然麻烦,但是掌握之后,一旦看哪个bean不顺眼就可以方便的取而代之。强大灵活!
3.0 xml的schema, 因为是用bean的方式配置嘛,默认命名空间当然是用beans方便。
3.1 web项目部署描述
提醒一下,如果SpringSecurity和Struts2共同使用的话 org.springframework.web.filter.DelegatingFilterProxy 一定要配置在
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter前面。要不然你的SpringSecurity根本不会起任何作用的。
当然如果使用的是 SpringMVC框架的话那根本无所谓配置顺序,因为SpringMVC的核心转发器是一个Servlet的实现。
3.2 配置SpringSecurity过滤器组 (我一般就用这九个) 顺序很重要
3.3 channelProcessingFilter: 常用来将某些HTTP协议的URL重定向到HTTPS协议
3.4 concurrencyFilter:HttpSession并发过滤器
3.5 securityContextPersistenceFilter:获取或存储一个SecurityContext
3.6 logoutFilter:监控一个实现退出功能的URL
这个bean没有没有默认构造方法。
3.7 usernamePasswordProcessingFilter:处理用户登录请求
3.8 rememberMeProcessingFilter: 实现"记住我"功能
被我注释掉的jdbcRememberMeTokenRepository需要一个数据库表
这个表用来持久化RememberMeToken,生产环境一般还是要这样做的。
3.9 anonymousProcessingFilter:如果用户不能通过验证则给添加一个匿名用户的角色
3.10 exceptionTranslationFilter: 验证通不过?没有访问权限?这个Filter决定如果出现异常了到底应该这么办。
3.11 filterSecurityInterceptor:核心过滤器的最后一个。它完成最终的授权判断
下面的配置有点多,那是因为filterSecurityInterceptor是个懒家伙。
它把工作委托AuthenticationManager接口,AuthenticationManager接口也不真的干活,
它委托多个AuthenticationProvider接口,当然其中一个AuthenticationProvider还是要
把工作委托给我们的UserDetailsService实现的。最后投票决定到最终结果。
3.12 其他的工具bean
(四) How to
4.1 在MVC框架里,我该如何得到现在已经登录的用户?
4.2 登录页面我要做后端验证,我该怎么办?
usernamePasswordProcessingFilter实际完成这个功能,自己写这个类。
那您就把ROLE_ADMIN角色写死在jsp中
ROLE_ADMIN角色删除不了
如果其他角色想访问该资源,还得改源码
小弟糊涂,还望大·侠指点!
方便的话加我qq459109544
谢谢
角色写死在配置文件里,如果今后角色是可以维护的怎办
以上的配置只是例子而已。
你可以这样的
hasRole是一个SpEL的函数名,个人也感觉它起名字有问题,这个函数实际上是根据
GrantedAuthority接口来判断。而跟我们定义的Role或者Permission没有直接关系。
请问<security:intercept-url pattern="/**" access="hasRole('PERMISSION_CAN_DO_SOMETHING')" />
PERMISSION_CAN_DO_SOMETHING是表达什么意思?写死在这里吗?
页面标签<sec:authorize url="/add*">不好使,看官方文档说在应用程序上下文必须有webapplicationContext实例,才能用 google上查不到 请帮忙解答,非常感谢!
你好。
"PERMISSION_CAN_DO_SOMETHING"就是"GrantedAuthority"接口的"generateGrantedAuthority()"方法的返回值,我是用Hibernate实现的UserDetailsService从数据库里把这个字符串取出来。
这个字符串就是一个用户有没有某种权限判断的依据。
<sec:authorize url="/add*">我也没有用过。
我现在是把资源url写在DB中,配置文件中不需要
也是自定义的filter
使用ss3提供的JSP标签,<sec:authorize 来控制页面上显示的内容,请问您是怎么做到的?
角色写死在配置文件里,如果今后角色是可以维护的怎办
以上的配置只是例子而已。
你可以这样的
hasRole是一个SpEL的函数名,个人也感觉它起名字有问题,这个函数实际上是根据
GrantedAuthority接口来判断。而跟我们定义的Role或者Permission没有直接关系。
请问<security:intercept-url pattern="/**" access="hasRole('PERMISSION_CAN_DO_SOMETHING')" />
PERMISSION_CAN_DO_SOMETHING是表达什么意思?写死在这里吗?
页面标签<sec:authorize url="/add*">不好使,看官方文档说在应用程序上下文必须有webapplicationContext实例,才能用 google上查不到 请帮忙解答,非常感谢!
你好。
"PERMISSION_CAN_DO_SOMETHING"就是"GrantedAuthority"接口的"generateGrantedAuthority()"方法的返回值,我是用Hibernate实现的UserDetailsService从数据库里把这个字符串取出来。
这个字符串就是一个用户有没有某种权限判断的依据。
<sec:authorize url="/add*">我也没有用过。
角色写死在配置文件里,如果今后角色是可以维护的怎办
以上的配置只是例子而已。
你可以这样的
hasRole是一个SpEL的函数名,个人也感觉它起名字有问题,这个函数实际上是根据
GrantedAuthority接口来判断。而跟我们定义的Role或者Permission没有直接关系。
请问<security:intercept-url pattern="/**" access="hasRole('PERMISSION_CAN_DO_SOMETHING')" />
PERMISSION_CAN_DO_SOMETHING是表达什么意思?写死在这里吗?
页面标签<sec:authorize url="/add*">不好使,看官方文档说在应用程序上下文必须有webapplicationContext实例,才能用 google上查不到 请帮忙解答,非常感谢!
角色写死在配置文件里,如果今后角色是可以维护的怎办
以上的配置只是例子而已。
你可以这样的
hasRole是一个SpEL的函数名,个人也感觉它起名字有问题,这个函数实际上是根据
GrantedAuthority接口来判断。而跟我们定义的Role或者Permission没有直接关系。
(一) 数据库与实体类设计(mysql)
-- 权限 DROP TABLE IF EXISTS `me`.`tbl_permission` ; CREATE TABLE IF NOT EXISTS `me`.`tbl_permission` ( `_id` INT NOT NULL AUTO_INCREMENT , `_name` VARCHAR(45) NOT NULL , `_desc` VARCHAR(255) NULL , PRIMARY KEY (`_id`) , UNIQUE INDEX `_name_UNIQUE` (`_name` ASC) ) ENGINE = InnoDB; -- 角色 DROP TABLE IF EXISTS `me`.`tbl_role` ; CREATE TABLE IF NOT EXISTS `me`.`tbl_role` ( `_id` INT NOT NULL AUTO_INCREMENT , `_name` VARCHAR(45) NOT NULL , PRIMARY KEY (`_id`) , UNIQUE INDEX `_name_UNIQUE` (`_name` ASC) ) ENGINE = InnoDB; -- 角色权限关联表 DROP TABLE IF EXISTS `me`.`tbl_role_permission` ; CREATE TABLE IF NOT EXISTS `me`.`tbl_role_permission` ( `_id_permission` INT NOT NULL , `_id_role` INT NOT NULL , PRIMARY KEY (`_id_permission`, `_id_role`) , INDEX `fk_permission_QENOQPN` (`_id_permission` ASC) , INDEX `fk_role_PQEMAQWENGHJ` (`_id_role` ASC) , CONSTRAINT `fk_permission_QENOQPN` FOREIGN KEY (`_id_permission` ) REFERENCES `me`.`tbl_permission` (`_id` ) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `fk_role_PQEMAQWENGHJ` FOREIGN KEY (`_id_role` ) REFERENCES `me`.`tbl_role` (`_id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB; -- 用户表 DROP TABLE IF EXISTS `me`.`tbl_user` ; CREATE TABLE IF NOT EXISTS `me`.`tbl_user` ( `_id` INT NOT NULL AUTO_INCREMENT , `_username` VARCHAR(45) NOT NULL , `_password` CHAR(32) NULL , `_disabled` CHAR(1) NULL , PRIMARY KEY (`_id`) , UNIQUE INDEX `_username_UNIQUE` (`_username` ASC) , UNIQUE INDEX `_disabled_UNIQUE` (`_disabled` ASC) ) ENGINE = InnoDB; -- 用户Email表 跟SpringSecurity没有关系 DROP TABLE IF EXISTS `me`.`tbl_email` ; CREATE TABLE IF NOT EXISTS `me`.`tbl_email` ( `_user_id` INT NOT NULL , `_email` VARCHAR(70) NOT NULL , `_order` INT NOT NULL , PRIMARY KEY (`_user_id`, `_email`) , UNIQUE INDEX `_email_UNIQUE` (`_email` ASC) , INDEX `fk_user_id_QWZLAKUIG` (`_user_id` ASC) , CONSTRAINT `fk_user_id_QWZLAKUIG` FOREIGN KEY (`_user_id` ) REFERENCES `me`.`tbl_user` (`_id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB; -- 用户角色关联表 DROP TABLE IF EXISTS `me`.`tbl_user_role` ; CREATE TABLE IF NOT EXISTS `me`.`tbl_user_role` ( `_user_id` INT NOT NULL , `_role_id` INT NOT NULL , PRIMARY KEY (`_user_id`, `_role_id`) , INDEX `fk_user_id_POIUYHJNB` (`_user_id` ASC) , INDEX `fk_role_id_MNHTRFVD` (`_role_id` ASC) , CONSTRAINT `fk_user_id_POIUYHJNB` FOREIGN KEY (`_user_id` ) REFERENCES `me`.`tbl_user` (`_id` ) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `fk_role_id_MNHTRFVD` FOREIGN KEY (`_role_id` ) REFERENCES `me`.`tbl_role` (`_id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB;
显然这种设计方式实际上比较常见的,用户与角色是多对多关系;角色与权限也是多对多关系。
下面是实体类(为了节约篇幅getter和setter以及ORM相关的元注释略去)
import java.io.Serializable; import java.util.Set; import org.springframework.security.core.GrantedAuthority; /** 权限类实现 GrantedAuthority接口 */ public class Permission implements Serializable, GrantedAuthority { private Integer id; private String name; private String description; private Set<Role> roles; public String getAuthority() { return getName(); } }
import java.io.Serializable; import java.util.HashSet; import java.util.Set; import org.springframework.security.core.GrantedAuthority; /** 角色类 */ public class Role implements Serializable { private Integer id; private String name; private Set<Permission> permissions = new HashSet<Permission>(); private Set<User> users = new HashSet<User>(); // 为了简便起见 ROLE 和 Permission都视为一种权限 public GrantedAuthority generateGrantedAuthority() { return new GrantedAuthority() { public String getAuthority() { return getName(); } }; } }
import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; /** 用户类实现UserDetails接口 */ public class User implements Serializable, UserDetails { private Integer id; private String username; private String password; private List<String> emails = new ArrayList<String>(); // 和SpringSecurity没有关系的业务字段 private String disabled; private Set<Role> roles = new HashSet<Role>(); public Collection<? extends GrantedAuthority> getAuthorities() { List<GrantedAuthority> list = new ArrayList<GrantedAuthority>(); for (Role role : roles) { list.add(role.generateGrantedAuthority()); for (Permission permission : role.getPermissions()) { list.add(permission); } } // 排序其实没有必要 // Collections.sort(list, GrantedAuthorityComparators.REVERSE); return list; } public String getPassword() { return password; } public String getUsername() { return username; } public boolean isAccountNonExpired() { return true; } public boolean isAccountNonLocked() { return true; } public boolean isCredentialsNonExpired() { return true; } public boolean isEnabled() { return disabled.equalsIgnoreCase("F"); } } class GrantedAuthorityComparators implements Comparator<GrantedAuthority> { public static final Comparator<GrantedAuthority> DEFAULT = new GrantedAuthorityComparators(); public static final Comparator<GrantedAuthority> REVERSE = new Comparator<GrantedAuthority>() { public int compare(GrantedAuthority o1, GrantedAuthority o2) { return - DEFAULT.compare(o1, o2); } }; private GrantedAuthorityComparators() { super(); } public int compare(GrantedAuthority g1, GrantedAuthority g2) { return g1.getAuthority().compareTo(g2.getAuthority()); } }
(二) 编写重要的UserDetailsService实现类
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.yingzhuo.me.domain.User; @Transactional(propagation = Propagation.SUPPORTS, readOnly = true) public interface UserDao extends UserDetailsService { public User findUserByUsernameAndPassword(String username, String password); }
import org.hibernate.Query; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Repository; @Repository("userDao") public class UserDaoImpl extends BaseDao implements UserDao { public User findUserByUsernameAndPassword(String username, String password) { final String hql = "from User as u left join fetch u.roles where u.username = :username and u.password = :password"; Query query = getSession().createQuery(hql) .setParameter("username", username) .setParameter("password", password); return (User) query.uniqueResult(); } public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { final String hql = "from User as u left join fetch u.roles where u.username = :username"; Query query = getSession().createQuery(hql).setParameter("username", username); User user = (User) query.uniqueResult(); if (user == null) { throw new UsernameNotFoundException("Username '" + username + "' not found"); } // 取消延迟加载 for (Role role : user.getRoles()) { for (Permission per : role.getPermissions()) { per.getName(); } } return user; } }
虽然SpringSecurity框架提供的接口很多,真正要亲自实现的不多三个而已
- org.springframework.security.core.GrantedAuthority
- org.springframework.security.core.userdetails.UserDetails
- org.springframework.security.core.userdetails.UserDetailsService
(三) 编写Spring Security 配置文件
尽管SpringSecurity提供了<http>元素来简化配置,简化过后有相当多的细节被隐藏起来了。
有时候想改变一下框架的默认行为十分不便。我还是用传统的Bean方式。
这样虽然麻烦,但是掌握之后,一旦看哪个bean不顺眼就可以方便的取而代之。强大灵活!
3.0 xml的schema, 因为是用bean的方式配置嘛,默认命名空间当然是用beans方便。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:security="http://www.springframework.org/schema/security" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd"> </beans>
3.1 web项目部署描述
<!-- Spring Security 核心拦截器组 --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Web Application Context --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring-bean.xml classpath:spring-orm.xml classpath:spring-security.xml </param-value> </context-param> <!-- 支持SpringSecurity Session并发控制 --> <listener> <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> </listener>
提醒一下,如果SpringSecurity和Struts2共同使用的话 org.springframework.web.filter.DelegatingFilterProxy 一定要配置在
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter前面。要不然你的SpringSecurity根本不会起任何作用的。
当然如果使用的是 SpringMVC框架的话那根本无所谓配置顺序,因为SpringMVC的核心转发器是一个Servlet的实现。
3.2 配置SpringSecurity过滤器组 (我一般就用这九个) 顺序很重要
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy"> <security:filter-chain-map request-matcher="ant" > <security:filter-chain pattern="/**" filters=" channelProcessingFilter, concurrencyFilter, securityContextPersistenceFilter, logoutFilter, usernamePasswordProcessingFilter, rememberMeProcessingFilter, anonymousProcessingFilter, exceptionTranslationFilter, filterSecurityInterceptor" /> </security:filter-chain-map> </bean>
3.3 channelProcessingFilter: 常用来将某些HTTP协议的URL重定向到HTTPS协议
<bean id="channelProcessingFilter" class="org.springframework.security.web.access.channel.ChannelProcessingFilter"> <property name="channelDecisionManager" ref="channelDecisionManager" /> <property name="securityMetadataSource"> <security:filter-security-metadata-source request-matcher="ant"> <!-- <security:intercept-url pattern="/just/test" access="REQUIRES_SECURE_CHANNEL" /> --> <security:intercept-url pattern="/**" access="ANY_CHANNEL" /> </security:filter-security-metadata-source> </property> </bean> <bean id="channelDecisionManager" class="org.springframework.security.web.access.channel.ChannelDecisionManagerImpl"> <property name="channelProcessors"> <list> <ref local="secureChannelProcessor" /> <ref local="insecureChannelProcessor" /> </list> </property> </bean> <bean id="secureChannelProcessor" class="org.springframework.security.web.access.channel.SecureChannelProcessor" /> <bean id="insecureChannelProcessor" class="org.springframework.security.web.access.channel.InsecureChannelProcessor" />
3.4 concurrencyFilter:HttpSession并发过滤器
<bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter"> <property name="sessionRegistry" ref="sessionRegistry" /> <property name="expiredUrl" value="/common/session-expired" /> <!-- 配置Session过期后重定向的地址 --> </bean> <bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" /> <bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy"> <constructor-arg index="0" ref="sessionRegistry" /> <property name="maximumSessions" value="1" /> </bean>
3.5 securityContextPersistenceFilter:获取或存储一个SecurityContext
<bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter" />
3.6 logoutFilter:监控一个实现退出功能的URL
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"> <constructor-arg index="0" value="/common/login" /> <!-- 退出后重定向 --> <constructor-arg index="1"> <array> <ref local="logoutHandler" /> <ref local="rememberMeServices" /> </array> </constructor-arg> <property name="filterProcessesUrl" value="/common/logout"/> <!-- 监控的URL --> </bean> <!-- 这个Bean注入到logoutFilter中去,它实际负责最后的扫尾工作,如把HttpSession实例删除 --> <bean id="logoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"> <property name="invalidateHttpSession" value="true" /> </bean>
这个bean没有没有默认构造方法。
3.7 usernamePasswordProcessingFilter:处理用户登录请求
<bean id="usernamePasswordProcessingFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> <property name="filterProcessesUrl" value="/common/login-process"/> <property name="usernameParameter" value="username"/> <property name="passwordParameter" value="password"/> <property name="authenticationManager" ref="customAuthenticationManager"/> <property name="rememberMeServices" ref="rememberMeServices"/> <property name="authenticationFailureHandler" ref="authenticationFailureHandler"/> <property name="sessionAuthenticationStrategy" ref="sas" /> </bean> <!-- 这个Bean注入到usernamePasswordProcessingFilter中去,他决定用户名和密码验证失败之后的动作 注意: 应设置行为为转发方式,否则保存在HttpServletRequest实例中的错误信息会因为重定向而丢失。 --> <bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <property name="defaultFailureUrl" value="/common/login"/> <property name="useForward" value="true" /> </bean>
3.8 rememberMeProcessingFilter: 实现"记住我"功能
<bean id="rememberMeProcessingFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter"> <property name="rememberMeServices" ref="rememberMeServices"/> <property name="authenticationManager" ref="customAuthenticationManager" /> </bean> <bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices"> <property name="key" value="#{securityKeys['remember-me']}" /> <!-- KEY 用于加密 两个一定要相同 --> <property name="parameter" value="_remember_me" /> <property name="tokenValiditySeconds" value="7200" /> <property name="tokenRepository" ref="inMemoryTokenRepository" /> <!-- 下面就是我自己实现的UserDetailsService 我给了alias "hibernateUserDetailsService" --> <property name="userDetailsService" ref="hibernateUserDetailsService" /> </bean> <bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider"> <property name="key" value="#{securityKeys['remember-me']}" /> <!-- KEY 用于加密 两个一定要相同 --> </bean> <bean id="inMemoryTokenRepository" class="org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl" /> <!-- <bean id="jdbcRememberMeTokenRepository" class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl"> <property name="dataSource" ref="dataSource" /> </bean> -->
被我注释掉的jdbcRememberMeTokenRepository需要一个数据库表
这个表用来持久化RememberMeToken,生产环境一般还是要这样做的。
create table persistent_logins ( username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null );
3.9 anonymousProcessingFilter:如果用户不能通过验证则给添加一个匿名用户的角色
<bean id="anonymousProcessingFilter" class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter"> <property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/> <property name="key" value="#{securityKeys['anonymous']}"/> </bean>
3.10 exceptionTranslationFilter: 验证通不过?没有访问权限?这个Filter决定如果出现异常了到底应该这么办。
<bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter"> <property name="authenticationEntryPoint" ref="authenticationEntryPoint" /> <property name="accessDeniedHandler" ref="accessDeniedHandler" /> </bean> <bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <property name="useForward" value="false" /> <property name="loginFormUrl" value="/common/login" /> </bean> <bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl"> <property name="errorPage" value="/common/error"/> </bean>
3.11 filterSecurityInterceptor:核心过滤器的最后一个。它完成最终的授权判断
下面的配置有点多,那是因为filterSecurityInterceptor是个懒家伙。
它把工作委托AuthenticationManager接口,AuthenticationManager接口也不真的干活,
它委托多个AuthenticationProvider接口,当然其中一个AuthenticationProvider还是要
把工作委托给我们的UserDetailsService实现的。最后投票决定到最终结果。
<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <property name="authenticationManager" ref="customAuthenticationManager" /> <property name="accessDecisionManager" ref="affirmativeBased" /> <property name="securityMetadataSource"> <security:filter-security-metadata-source use-expressions="true"> <security:intercept-url pattern="/common/login" access="permitAll" /> <security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" /> </security:filter-security-metadata-source> </property> </bean> <bean id="customAuthenticationManager" class="org.springframework.security.authentication.ProviderManager"> <property name="authenticationEventPublisher" ref="defaultAuthEventPublisher"/> <property name="providers"> <list> <ref local="daoAuthenticationProvider"/> <ref local="anonymousAuthenticationProvider"/> <ref local="rememberMeAuthenticationProvider"/> </list> </property> </bean> <!-- 这个Bean决定了投票策略,decisionVoters只要有任意一个决定通过,那么结果就是通过。 --> <bean class="org.springframework.security.access.vote.AffirmativeBased" id="affirmativeBased"> <property name="decisionVoters"> <list> <ref bean="roleVoter"/> <ref bean="expressionVoter"/> <ref bean="authenticatedVoter"/> </list> </property> </bean> <bean class="org.springframework.security.access.vote.RoleVoter" id="roleVoter" /> <bean class="org.springframework.security.access.vote.AuthenticatedVoter" id="authenticatedVoter" /> <bean id="defaultAuthEventPublisher" class="org.springframework.security.authentication.DefaultAuthenticationEventPublisher"/> <bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> <property name="passwordEncoder" ref="md5PasswordEncoder"/> <property name="userDetailsService" ref="hibernateUserDetailsService" /> <!-- <property name="saltSource" ref="saltSource"/> --> </bean> <bean id="anonymousAuthenticationProvider" class="org.springframework.security.authentication.AnonymousAuthenticationProvider"> <property name="key" value="#{securityKeys['anonymous']}" /> </bean> <bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" id="expressionHandler"/> <bean class="org.springframework.security.web.access.expression.WebExpressionVoter" id="expressionVoter"> <property name="expressionHandler" ref="expressionHandler"/> </bean>
3.12 其他的工具bean
<util:properties id="securityKeys"> <prop key="remember-me">182301IEKO1L73C181891TLTKABCNKA1956A7G9UPQXN</prop> <prop key="anonymous">BF93JFJ091N00Q7HF</prop> </util:properties> <alias name="userDao" alias="hibernateUserDetailsService"/> <bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="md5PasswordEncoder" /> <!-- 如果使用 Sha加密的话,可以用一用 --> <!-- <bean class="org.springframework.security.authentication.dao.ReflectionSaltSource" id="saltSource"> <property name="userPropertyToUse" value="id"/> </bean> -->
(四) How to
4.1 在MVC框架里,我该如何得到现在已经登录的用户?
User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
4.2 登录页面我要做后端验证,我该怎么办?
usernamePasswordProcessingFilter实际完成这个功能,自己写这个类。
public class ValidatedUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter { private Logger logger = LoggerFactory.getLogger(getClass()); @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { Authentication result = null; Locale locale = request.getLocale(); try { result = super.attemptAuthentication(request, response); logger.debug("登录成功"); } catch (AuthenticationException failed) { logger.debug("登录失败"); String msg = super.messages.getMessage("validator.login.fail", locale); request.setAttribute("fail", msg); throw failed; } return result; } } // 注意这个类是实现了MessageSourceAware接口的。你加载了国际化文件的MessageSource用就好了。但是一定要配置在 WebApplicationContext里,不要配置在springMVC特有的配置文件里。
- spring-security.zip (3.2 KB)
- 下载次数: 256
评论
10 楼
wellbeing_wang
2013-12-22
你好:
这个相关源码能否提供一份?谢谢!wangwenbincn@163.com
这个相关源码能否提供一份?谢谢!wangwenbincn@163.com
9 楼
guang.027
2013-12-11
能否给相关源,谢谢,flash8627@hotmail.com
8 楼
leon.s.kennedy
2012-05-10
yingzhor 写道
我就是用的这个呀。
<sec:authorize access="hasRole('ROLE_ADMIN')">
这段文本只有管理员可见
</sec:authorize>
如果登录的用户有管理员的角色的话,中间的文本他就可以看见了。
<sec:authorize access="hasRole('ROLE_ADMIN')">
这段文本只有管理员可见
</sec:authorize>
如果登录的用户有管理员的角色的话,中间的文本他就可以看见了。
那您就把ROLE_ADMIN角色写死在jsp中
ROLE_ADMIN角色删除不了
如果其他角色想访问该资源,还得改源码
小弟糊涂,还望大·侠指点!
方便的话加我qq459109544
谢谢
7 楼
yingzhor
2012-05-10
我就是用的这个呀。
<sec:authorize access="hasRole('ROLE_ADMIN')">
这段文本只有管理员可见
</sec:authorize>
如果登录的用户有管理员的角色的话,中间的文本他就可以看见了。
<sec:authorize access="hasRole('ROLE_ADMIN')">
这段文本只有管理员可见
</sec:authorize>
如果登录的用户有管理员的角色的话,中间的文本他就可以看见了。
6 楼
leon.s.kennedy
2012-05-10
yingzhor 写道
leon.s.kennedy 写道
yingzhor 写道
引用
角色写死在配置文件里,如果今后角色是可以维护的怎办
<security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
以上的配置只是例子而已。
你可以这样的
<security:intercept-url pattern="/**" access="hasRole('PERMISSION_CAN_DO_SOMETHING')" />
hasRole是一个SpEL的函数名,个人也感觉它起名字有问题,这个函数实际上是根据
GrantedAuthority接口来判断。而跟我们定义的Role或者Permission没有直接关系。
请问<security:intercept-url pattern="/**" access="hasRole('PERMISSION_CAN_DO_SOMETHING')" />
PERMISSION_CAN_DO_SOMETHING是表达什么意思?写死在这里吗?
页面标签<sec:authorize url="/add*">不好使,看官方文档说在应用程序上下文必须有webapplicationContext实例,才能用 google上查不到 请帮忙解答,非常感谢!
你好。
"PERMISSION_CAN_DO_SOMETHING"就是"GrantedAuthority"接口的"generateGrantedAuthority()"方法的返回值,我是用Hibernate实现的UserDetailsService从数据库里把这个字符串取出来。
这个字符串就是一个用户有没有某种权限判断的依据。
<sec:authorize url="/add*">我也没有用过。
我现在是把资源url写在DB中,配置文件中不需要
也是自定义的filter
使用ss3提供的JSP标签,<sec:authorize 来控制页面上显示的内容,请问您是怎么做到的?
5 楼
yingzhor
2012-05-10
leon.s.kennedy 写道
yingzhor 写道
引用
角色写死在配置文件里,如果今后角色是可以维护的怎办
<security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
以上的配置只是例子而已。
你可以这样的
<security:intercept-url pattern="/**" access="hasRole('PERMISSION_CAN_DO_SOMETHING')" />
hasRole是一个SpEL的函数名,个人也感觉它起名字有问题,这个函数实际上是根据
GrantedAuthority接口来判断。而跟我们定义的Role或者Permission没有直接关系。
请问<security:intercept-url pattern="/**" access="hasRole('PERMISSION_CAN_DO_SOMETHING')" />
PERMISSION_CAN_DO_SOMETHING是表达什么意思?写死在这里吗?
页面标签<sec:authorize url="/add*">不好使,看官方文档说在应用程序上下文必须有webapplicationContext实例,才能用 google上查不到 请帮忙解答,非常感谢!
你好。
"PERMISSION_CAN_DO_SOMETHING"就是"GrantedAuthority"接口的"generateGrantedAuthority()"方法的返回值,我是用Hibernate实现的UserDetailsService从数据库里把这个字符串取出来。
这个字符串就是一个用户有没有某种权限判断的依据。
<sec:authorize url="/add*">我也没有用过。
4 楼
leon.s.kennedy
2012-05-10
yingzhor 写道
引用
角色写死在配置文件里,如果今后角色是可以维护的怎办
<security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
以上的配置只是例子而已。
你可以这样的
<security:intercept-url pattern="/**" access="hasRole('PERMISSION_CAN_DO_SOMETHING')" />
hasRole是一个SpEL的函数名,个人也感觉它起名字有问题,这个函数实际上是根据
GrantedAuthority接口来判断。而跟我们定义的Role或者Permission没有直接关系。
请问<security:intercept-url pattern="/**" access="hasRole('PERMISSION_CAN_DO_SOMETHING')" />
PERMISSION_CAN_DO_SOMETHING是表达什么意思?写死在这里吗?
页面标签<sec:authorize url="/add*">不好使,看官方文档说在应用程序上下文必须有webapplicationContext实例,才能用 google上查不到 请帮忙解答,非常感谢!
3 楼
yingzhor
2012-05-03
引用
角色写死在配置文件里,如果今后角色是可以维护的怎办
<security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
以上的配置只是例子而已。
你可以这样的
<security:intercept-url pattern="/**" access="hasRole('PERMISSION_CAN_DO_SOMETHING')" />
hasRole是一个SpEL的函数名,个人也感觉它起名字有问题,这个函数实际上是根据
GrantedAuthority接口来判断。而跟我们定义的Role或者Permission没有直接关系。
2 楼
yingzhor
2012-05-03
我不太了解你所指的“把角色写死在配置文件里”是什么意思。
我并没有这样做,GrantedAuthority的实现类是Permission 而不是 Role。
而Permission也是数据库相关的实体类。也就是说,实际上权限的信息是存放在数据库里的。
因为我的文章只是做个简单的Demo, 我其实偷换了一下概念,让Role和Permission都具有了
GrantedAuthority定义的语义。在生产上我们不会这么做。
前台页面标签中,如何控制显示连接?也把角色写死吗?
SpringSecurity提供了JSP标签,用来决定显示/隐藏页面的内容。
<security:authorize /> 具体使用方法请查看官方文档。
还用种匹配url的标签,您不妨试试看
谢谢,我知道Spring Security还特别提供了一个security的xml schema,
但是个人觉得使用那样的配置方式虽然简单,但是隐藏的细节太多。
有时候想改变一下spring security框架的默认行为就不是那么方便了。
我并没有这样做,GrantedAuthority的实现类是Permission 而不是 Role。
而Permission也是数据库相关的实体类。也就是说,实际上权限的信息是存放在数据库里的。
因为我的文章只是做个简单的Demo, 我其实偷换了一下概念,让Role和Permission都具有了
GrantedAuthority定义的语义。在生产上我们不会这么做。
引用
前台页面标签中,如何控制显示连接?也把角色写死吗?
SpringSecurity提供了JSP标签,用来决定显示/隐藏页面的内容。
<security:authorize /> 具体使用方法请查看官方文档。
引用
还用种匹配url的标签,您不妨试试看
谢谢,我知道Spring Security还特别提供了一个security的xml schema,
但是个人觉得使用那样的配置方式虽然简单,但是隐藏的细节太多。
有时候想改变一下spring security框架的默认行为就不是那么方便了。
1 楼
leon.s.kennedy
2012-05-03
博主您好
您如此配置ss3文件,把角色写死在配置文件里,如果今后角色是可以维护的怎办?
前台页面标签中,如何控制显示连接?也把角色写死吗?
还用种匹配url的标签,您不妨试试看
您如此配置ss3文件,把角色写死在配置文件里,如果今后角色是可以维护的怎办?
前台页面标签中,如何控制显示连接?也把角色写死吗?
还用种匹配url的标签,您不妨试试看
发表评论
-
SpringMVC杂记(十八) ServletRequestAttributes的应用
2014-02-28 12:38 14212看了一下SpringMVC的源代码,原来SpringMVC也提 ... -
SpringWebflow杂记(一) 框架初探,与SpringMVC的集成
2013-10-23 17:18 1711今日研究了一下SpringWebFlow这个项目,作为Spri ... -
SpringMVC杂记(十六) spring-mvc 与 openid4java
2013-10-12 15:25 3869SpringMVC杂记(十六) spring-mvc 与 op ... -
SpringMVC杂记(十五) spring-mvc controller 的切面
2013-08-01 19:42 6136SpringMVC杂记(十五) spring-mvc cont ... -
Spring集成CXF
2013-06-24 15:53 1569Spring集成CXF 零) jar依赖 <dep ... -
SpringMVC杂记(十四) Ajax方式的JSR303认证
2013-06-13 07:29 4520自己定义一个Exception,用来表示数据绑定失败 im ... -
SpringMVC杂记(十三) 使用FreeMarker作为视图层
2013-06-09 11:55 3398实在没什么好说的,直接上配置文件好了 <bean i ... -
SpringMVC杂记(十二) 自定义Interceptor从Active Directory得到域信息
2013-06-04 14:04 3201一)最近项目中要求实现Web应用的SSO(Single Sig ... -
通过spring,javamail,和freemarker集成发送HTML方式的电子邮件
2013-05-30 14:02 4870一) 现在项目中用的javamail和org.springfr ... -
SpringMVC杂记(十一) 使用Excel视图
2013-04-06 16:06 6624SpringMVC杂记(十一) 使用Excel视图 一) 其 ... -
Spring集成junit
2012-12-24 10:43 1503package junit; import org. ... -
SpringMVC杂记(十) 验证码生成
2012-11-06 10:18 2783以前写过一篇关于这个的博客,现在用SpringMVC了,重写一 ... -
SpringMVC杂记(九) 模拟其他类型(非GET,POST)的请求
2012-10-22 10:49 26901) 以前一个小兄弟问我,SpringMVC是否可以使用很多浏 ... -
SpringMVC杂记(八) 使用阿里巴巴的fastjson
2012-07-21 08:27 102691) 国产开源软件要支持的 <dependency& ... -
ActiveMQ学习笔记(二) JMS与Spring
2012-06-24 10:21 7425上文可见,JMS Native API使用起来不是特别方便。好 ... -
SpringMVC杂记(七) Jackson与Hibernate LazyLoding无法正常工作解决办法
2012-03-21 13:35 7054SpringMVC杂记(七) Jackson与Hibernat ... -
SpringMVC杂记(六) 下载文件
2012-03-21 09:04 4278SpringMVC杂记(六) 下载文件 1) jar依赖 ... -
SpringMVC杂记(五) JSR303数据验证
2012-03-16 16:30 12434SpringMVC杂记(五) JSR303数据验证 1) 首 ... -
SpringMVC杂记(四) 数据绑定
2012-03-15 13:44 2256SpringMVC杂记(四) 数据绑定 1) 使用java. ... -
SpringMVC杂记(三) 向导型Controller的实现(基于SpringMVC 3.1.1)
2012-03-14 14:59 4661SpringMVC杂记(三) 向导型Controller的实现 ...
相关推荐
Spring Security 实践指南 Spring Security 是一个基于 Java 的安全框架,旨在提供身份验证、授权和访问控制等功能。下面是 Spring Security 的主要知识点: 一、身份验证(Authentication) 身份验证是指对用户...
这三份资料——"实战Spring Security 3.x.pdf"、"Spring Security 3.pdf" 和 "Spring Security使用手册.pdf" 将深入探讨这些概念,并提供实践指导,帮助读者掌握如何在实际项目中应用Spring Security。通过学习这些...
在"springsecurity学习笔记"中,你可能会涉及以下主题: - Spring Security的基本配置,包括web安全配置和全局安全配置。 - 如何自定义认证和授权流程,比如实现自定义的AuthenticationProvider和...
Spring Security 是一个强大的安全框架,用于为Java应用提供身份验证和授权服务。在这个完整的项目实例中...通过学习和实践这个项目,开发者能够深入理解Spring Security的工作原理,从而更有效地保护自己的Java应用。
《Spring Security 3.1 实践》 Spring Security 是一个强大的、高度可定制的身份验证和访问控制框架,广泛应用于Java企业级应用中。在Spring Security 3.1版本中,它提供了一套全面的安全解决方案,涵盖了从用户...
SpringSecurity是Java领域中一款强大的安全框架,主要用于Web应用程序的安全管理。它提供了全面的身份验证、授权、会话...通过深入学习和实践,我们可以更好地掌握SpringSecurity,为我们的应用构建坚固的安全防线。
在Spring Security的官方文档中,包含了详细的配置指南、API参考、示例代码和最佳实践,帮助开发者深入理解并有效使用这个框架。例如,5.1版本的新特性包括对Servlet和WebFlux的支持增强,以及与其他第三方库的集成...
在压缩包文件`spring_gateway_security_webflux`中,可能包含了示例代码或配置文件,用于演示如何在Spring Cloud Gateway中集成Spring Security,实现统一登录认证鉴权。这些资源可以帮助开发者更快地理解和实践上述...
### Spring Security 概述与应用实践 #### 一、引言 在当今互联网时代,网络安全问题日益凸显,尤其是Web应用程序的安全性受到了前所未有的关注。为了应对这些挑战,Spring Security 应运而生,成为了一个非常重要...
Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,用于Java应用程序。它提供了全面的安全解决方案,包括用户认证、权限授权、会话管理、CSRF防护以及基于HTTP的访问控制。在这个例子中,我们将...
Spring Security 2.5虽然已经较为老旧,但其设计理念和核心机制仍然适用于现代的开发实践。理解并熟练掌握这个版本,有助于深入理解Spring Security的工作原理,并为升级到更高版本或使用其他安全框架打下坚实基础。
SpringSecurity是Java领域中一款强大的安全框架,专为Spring和Spring Boot应用设计,提供全面的安全管理解决方案。...学习SpringSecurity时,理解其核心原理并结合实际项目进行实践,是掌握这个框架的关键。
在IT行业中,SpringBoot、SpringSecurity和WebSocket是三个非常重要的技术组件,它们分别在应用程序开发、安全管理和实时通信方面发挥着关键作用。本项目结合这三个技术,构建了一个整合的示例,旨在展示如何在...
Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,用于保护基于 Java 的应用程序。本教程将逐步引导你理解并使用 Spring Security 进行安全控制。以下是对关键知识点的详细说明: 1. **Spring ...
SpringSecurity是Java开发领域中广泛使用的安全框架,用于保护Web应用程序免受各种安全威胁。它提供了全面的身份验证、授权和访问控制功能。本压缩包包含了两份重要的SpringSecurity中文文档,分别为“Spring ...
6. **记住我功能**:Spring Security支持“记住我”功能,允许用户在一段时间内无须重新登录。这通过在客户端存储一个长期有效的令牌来实现。 7. **OAuth2整合**:Spring Security可以与OAuth2框架集成,支持第三方...
本教程配套源码旨在帮助开发者深入理解SpringSecurity的工作原理,通过实践提升在安全领域的技能。 在SpringSecurity中,核心概念主要包括以下几个部分: 1. **过滤器链**:SpringSecurity的核心是基于过滤器的Web...
Spring Security OAuth 是一个用于保护RESTful Web服务的框架,它为OAuth 1.0a和OAuth 2.0协议提供了全面的支持。在这个源码中,我们可能会看到如何将Spring Security与OAuth结合,以构建安全的Web应用程序和服务。...